Comparar commits
184 Commits
master
...
2.0.0-alpha2
| Autor | SHA1 | Data | |
|---|---|---|---|
| 253158cf1c | |||
| 8c34bdbcd7 | |||
| ecd3b58b28 | |||
| 41bac830c5 | |||
| 47b25d1c6d | |||
| 109de75c6a | |||
| 42856ec16a | |||
| faa43d51a9 | |||
| 3e4fce58fa | |||
| b0bddce017 | |||
| b5c69984e3 | |||
| a8375d0459 | |||
| 1f16b349d2 | |||
| 30019dfddd | |||
| 61eea7f4a1 | |||
| 6582e2ff06 | |||
| 8cfe21f6aa | |||
| 6815fc451f | |||
| 31643ee598 | |||
| 1a3bb25f5c | |||
| 181a61f16a | |||
| 763bde9ed1 | |||
| 0486db1e74 | |||
| 6185f156ea | |||
| d37e65c58c | |||
| 43efda72d4 | |||
| e55c0d4945 | |||
| a518833f96 | |||
| 49fe78643a | |||
| d2ef4c9831 | |||
| ec7b87d69c | |||
| 1e01e29f88 | |||
| e9f206606d | |||
| c5e4912319 | |||
| 63b7b18b17 | |||
| cfc008686b | |||
| e1237feb97 | |||
| cf88ec8333 | |||
| bba2dda59a | |||
| e2601f71e3 | |||
| 195c794e5d | |||
| 5732e0d72a | |||
| 187163763e | |||
| 15a32f4c78 | |||
| a76640c409 | |||
| 11773a5825 | |||
| 65de784be1 | |||
| 55cf07926c | |||
| bd39534c2f | |||
| 9dc63f0349 | |||
| edd93f27ce | |||
| 97a2232fbf | |||
| 29743e1d63 | |||
| 2bddccaaf0 | |||
| 8f5d702a86 | |||
| 24d32e9321 | |||
| 679fa4e72e | |||
| 9b4ebc3a05 | |||
| 7d4ead51f7 | |||
| bcd834c084 | |||
| 593a1eacc8 | |||
| d05d29aa66 | |||
| 4a3a9f1a21 | |||
| a89ede0d72 | |||
| 65ec618a48 | |||
| e63d5a3367 | |||
| 5b5463b6f9 | |||
| 205163641f | |||
| 09eae7ff28 | |||
| d46a174080 | |||
| 0c91bb96e0 | |||
| 9e9f436454 | |||
| cbd2fef80f | |||
| 996e471171 | |||
| 70f7dd4c7d | |||
| 9c106aa8ff | |||
| 7dcee4b40e | |||
| f12d1bcb56 | |||
| b9ab70f21b | |||
| c2d6e4c31f | |||
| a6c712323f | |||
| b93306788b | |||
| 2a62e0e04d | |||
| 8e5d8b8861 | |||
| 8b0b6194b2 | |||
| 675a9f827e | |||
| 235247eb12 | |||
| b3b5896329 | |||
| ecb1cde3fc | |||
| 9be48a73ea | |||
| 7e791e02f2 | |||
| 06d55e3501 | |||
| 37cfbdb802 | |||
| 8d1a857e75 | |||
| 42e2c237d4 | |||
| b22e1e3e9c | |||
| 635ec58616 | |||
| f44dd06826 | |||
| 02d7442e4f | |||
| 4ded634d75 | |||
| 80a25af502 | |||
| 9b2d2efc7a | |||
| 6b0e609935 | |||
| 74d3890ba9 | |||
| df4d2d2594 | |||
| b7dc2339f4 | |||
| edbb235668 | |||
| 92776ce0ac | |||
| e48c7f168b | |||
| 8a550852da | |||
| 6af94298ec | |||
| 1163efbcca | |||
| 3a32144d89 | |||
| e3519f5bd4 | |||
| 7d8b1712a7 | |||
| 54b51038ca | |||
| e774a893da | |||
| b03a057a76 | |||
| 48dd1cf024 | |||
| a2d477ac5e | |||
| 1352dfeb0f | |||
| d4e7765a50 | |||
| 73b579c962 | |||
| b67afcd727 | |||
| a10e245e5a | |||
| 181e866175 | |||
| d998c803d3 | |||
| a559ab85cd | |||
| c66edc9169 | |||
| b7606c7a8d | |||
| 12e2ace039 | |||
| ed4b9945f8 | |||
| 951e714e77 | |||
| 008bb1aab3 | |||
| 4cc24d475a | |||
| 4b8c9bc30d | |||
| 978ed1bc1e | |||
| 676765e808 | |||
| f2065265c8 | |||
| a6e2eec9e0 | |||
| 2e383da0d8 | |||
| e30a9d2a94 | |||
| 492292e94b | |||
| 454f519b6d | |||
| 56d53e3ad4 | |||
| 67b3d32218 | |||
| d7ad5b6340 | |||
| db1365c8ce | |||
| b5b0081108 | |||
| fff81c455d | |||
| ad972a0c5c | |||
| 872c92cd4b | |||
| 1d8d19d404 | |||
| ed6f234205 | |||
| 09c11440dd | |||
| e58421a08a | |||
| fb580a6e48 | |||
| f79ebdaa88 | |||
| b432a3d6db | |||
| ef4c46f2be | |||
| 69b1239aa1 | |||
| 4ef57315da | |||
| d26f37236d | |||
| 63e115e7a8 | |||
| 9f98334d6f | |||
| 15f724f146 | |||
| afb22d15ae | |||
| e709b13e77 | |||
| 460399f651 | |||
| 132272d140 | |||
| 9e4d90e110 | |||
| df91739b77 | |||
| d3f7071983 | |||
| d287a01b44 | |||
| 0eadc86d24 | |||
| c7b117631b | |||
| 0e29cfdfda | |||
| cf07df07d6 | |||
| 4b34bbadf9 | |||
| e13ada2b43 | |||
| 62b29282fd | |||
| 2814c8e44c | |||
| e67d198e69 | |||
| ae7552a916 |
@@ -5,3 +5,5 @@ node_modules/*
|
||||
custom/*
|
||||
|
||||
docs/index.md
|
||||
|
||||
bower_components/
|
||||
|
||||
externo
+6294
-3312
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+58
-3
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+2
-1
@@ -1,7 +1,8 @@
|
||||
# Chart.js
|
||||
|
||||
[](https://travis-ci.org/nnnick/Chart.js) [](https://codeclimate.com/github/nnnick/Chart.js)
|
||||
[](https://travis-ci.org/nnnick/Chart.js) [](https://codeclimate.com/github/nnnick/Chart.js)
|
||||
|
||||
# Version 2.0 is in early alpha. We are changing the internal data model to reduce copying, increase performance and expose a more flexible API.
|
||||
|
||||
*Simple HTML5 Charts using the canvas element* [chartjs.org](http://www.chartjs.org)
|
||||
|
||||
|
||||
+12
-10
@@ -1,11 +1,13 @@
|
||||
{
|
||||
"name": "Chart.js",
|
||||
"version": "1.0.2",
|
||||
"description": "Simple HTML5 Charts using the canvas element",
|
||||
"homepage": "https://github.com/nnnick/Chart.js",
|
||||
"author": "nnnick",
|
||||
"main": [
|
||||
"Chart.js"
|
||||
],
|
||||
"dependencies": {}
|
||||
}
|
||||
"name": "Chart.js",
|
||||
"version": "2.0.0-alpha",
|
||||
"description": "Simple HTML5 Charts using the canvas element",
|
||||
"homepage": "https://github.com/nnnick/Chart.js",
|
||||
"author": "nnnick",
|
||||
"main": [
|
||||
"Chart.js"
|
||||
],
|
||||
"devDependencies": {
|
||||
"jquery": "~2.1.4"
|
||||
}
|
||||
}
|
||||
|
||||
+165
-93
@@ -74,135 +74,207 @@ This concept was introduced in Chart.js 1.0 to keep configuration DRY, and allow
|
||||
|
||||
```javascript
|
||||
Chart.defaults.global = {
|
||||
// Boolean - Whether to animate the chart
|
||||
animation: true,
|
||||
// Animation settings
|
||||
animation: {
|
||||
// Length that animation should take in ms assuming 60fps.
|
||||
// Set to 0 to disable animation
|
||||
duration: 1000,
|
||||
|
||||
// Number - Number of animation steps
|
||||
animationSteps: 60,
|
||||
// Easing type. Possible values are:
|
||||
// [easeInOutQuart, linear, easeOutBounce, easeInBack, easeInOutQuad,
|
||||
// easeOutQuart, easeOutQuad, easeInOutBounce, easeOutSine, easeInOutCubic,
|
||||
// easeInExpo, easeInOutBack, easeInCirc, easeInOutElastic, easeOutBack,
|
||||
// easeInQuad, easeInOutExpo, easeInQuart, easeOutQuint, easeInOutCirc,
|
||||
// easeInSine, easeOutExpo, easeOutCirc, easeOutCubic, easeInQuint,
|
||||
// easeInElastic, easeInOutSine, easeInOutQuint, easeInBounce,
|
||||
// easeOutElastic, easeInCubic]
|
||||
easing: "easeOutQuart",
|
||||
|
||||
// String - Animation easing effect
|
||||
// Possible effects are:
|
||||
// [easeInOutQuart, linear, easeOutBounce, easeInBack, easeInOutQuad,
|
||||
// easeOutQuart, easeOutQuad, easeInOutBounce, easeOutSine, easeInOutCubic,
|
||||
// easeInExpo, easeInOutBack, easeInCirc, easeInOutElastic, easeOutBack,
|
||||
// easeInQuad, easeInOutExpo, easeInQuart, easeOutQuint, easeInOutCirc,
|
||||
// easeInSine, easeOutExpo, easeOutCirc, easeOutCubic, easeInQuint,
|
||||
// easeInElastic, easeInOutSine, easeInOutQuint, easeInBounce,
|
||||
// easeOutElastic, easeInCubic]
|
||||
animationEasing: "easeOutQuart",
|
||||
// Function - function to call each time an animation step occurs
|
||||
onProgress: function() {},
|
||||
|
||||
// Boolean - If we should show the scale at all
|
||||
showScale: true,
|
||||
// Function - function to call when animations finish
|
||||
onComplete: function() {},
|
||||
},
|
||||
|
||||
// Boolean - If we want to override with a hard coded scale
|
||||
scaleOverride: false,
|
||||
// Boolean - if true, resize the charts when the page resizes
|
||||
responsive: 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,
|
||||
// Boolean - if true, try to maintain the screen aspect ratio
|
||||
maintainAspectRatio: true,
|
||||
|
||||
// String - Colour of the scale line
|
||||
scaleLineColor: "rgba(0,0,0,.1)",
|
||||
// Array - events to bind tooltips to
|
||||
events: ["mousemove", "mouseout", "click", "touchstart", "touchmove", "touchend"],
|
||||
|
||||
// Number - Pixel width of the scale line
|
||||
scaleLineWidth: 1,
|
||||
// Hover settings
|
||||
hover: {
|
||||
// Function - called when the user hovers over the items.
|
||||
// Parameters: array of active elements
|
||||
onHover: null,
|
||||
|
||||
// Boolean - Whether to show labels on the scale
|
||||
scaleShowLabels: true,
|
||||
// String - hover mode. Options are 'single', 'label', and 'dataset'
|
||||
// 'single' gets the nearest element
|
||||
// 'label' gets all of the elements at the given dataset index (do not use for scatter charts)
|
||||
// 'dataset' gets all the elements in the given dataset
|
||||
mode: 'single',
|
||||
|
||||
// Interpolated JS string - can access value
|
||||
scaleLabel: "<%=value%>",
|
||||
// Number - duration (in ms) of the tooltip animation. 0 to disable
|
||||
animationDuration: 400,
|
||||
},
|
||||
|
||||
// Boolean - Whether the scale should stick to integers, not floats even if drawing space is there
|
||||
scaleIntegersOnly: true,
|
||||
// Function - click handler to bind to chart area
|
||||
onClick: null,
|
||||
|
||||
// Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
|
||||
scaleBeginAtZero: false,
|
||||
// Tooltip configuration
|
||||
tooltips: {
|
||||
// Boolean - if true show tooltips
|
||||
enabled: true,
|
||||
|
||||
// String - Scale label font declaration for the scale label
|
||||
scaleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
// Function - custom tooltip function to use
|
||||
custom: null,
|
||||
|
||||
// Number - Scale label font size in pixels
|
||||
scaleFontSize: 12,
|
||||
// String - color of tooltip background
|
||||
backgroundColor: "rgba(0,0,0,0.8)",
|
||||
|
||||
// String - Scale label font weight style
|
||||
scaleFontStyle: "normal",
|
||||
// String - fonts to use
|
||||
fontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
|
||||
// String - Scale label font colour
|
||||
scaleFontColor: "#666",
|
||||
// Number - font size
|
||||
fontSize: 10,
|
||||
|
||||
// Boolean - whether or not the chart should be responsive and resize when the browser does.
|
||||
responsive: false,
|
||||
// String - font style
|
||||
fontStyle: "normal",
|
||||
|
||||
// Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
|
||||
maintainAspectRatio: true,
|
||||
// String - font color
|
||||
fontColor: "#fff",
|
||||
|
||||
// Boolean - Determines whether to draw tooltips on the canvas or not
|
||||
showTooltips: true,
|
||||
// String - title fonts
|
||||
titleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
|
||||
// Function - Determines whether to execute the customTooltips function instead of drawing the built in tooltips (See [Advanced - External Tooltips](#advanced-usage-custom-tooltips))
|
||||
customTooltips: false,
|
||||
// Number - title font size
|
||||
titleFontSize: 12,
|
||||
|
||||
// Array - Array of string names to attach tooltip events
|
||||
tooltipEvents: ["mousemove", "touchstart", "touchmove"],
|
||||
// String - title font style
|
||||
titleFontStyle: "bold",
|
||||
|
||||
// String - Tooltip background colour
|
||||
tooltipFillColor: "rgba(0,0,0,0.8)",
|
||||
// String - title font color
|
||||
titleFontColor: "#fff",
|
||||
|
||||
// String - Tooltip label font declaration for the scale label
|
||||
tooltipFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
// Number -
|
||||
yPadding: 6,
|
||||
|
||||
// Number - Tooltip label font size in pixels
|
||||
tooltipFontSize: 14,
|
||||
// Number -
|
||||
xPadding: 6,
|
||||
|
||||
// String - Tooltip font weight style
|
||||
tooltipFontStyle: "normal",
|
||||
// Number -
|
||||
caretSize: 8,
|
||||
|
||||
// String - Tooltip label font colour
|
||||
tooltipFontColor: "#fff",
|
||||
// Number - radius of rounded corners
|
||||
cornerRadius: 6,
|
||||
|
||||
// String - Tooltip title font declaration for the scale label
|
||||
tooltipTitleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
// Number -
|
||||
xOffset: 10,
|
||||
|
||||
// Number - Tooltip title font size in pixels
|
||||
tooltipTitleFontSize: 14,
|
||||
// String - template string to use for tooltips in single mode
|
||||
template: [
|
||||
'<% if(label){ %>',
|
||||
'<%=label %>:',
|
||||
'<% } %>',
|
||||
'<%=value %>',
|
||||
].join(''),
|
||||
|
||||
// String - Tooltip title font weight style
|
||||
tooltipTitleFontStyle: "bold",
|
||||
// String - template string to use for tooltips in label mode
|
||||
multiTemplate: [
|
||||
'<%if (datasetLabel){ %>',
|
||||
'<%=datasetLabel %>:',
|
||||
'<% } %>',
|
||||
'<%=value %>'
|
||||
].join(''),
|
||||
|
||||
// String - Tooltip title font colour
|
||||
tooltipTitleFontColor: "#fff",
|
||||
// String -
|
||||
multiKeyBackground: '#fff',
|
||||
},
|
||||
|
||||
// Number - pixel width of padding around tooltip text
|
||||
tooltipYPadding: 6,
|
||||
// String - default grey color. 'rgba(0,0,0,0.1)'
|
||||
defaultColor: defaultColor,
|
||||
|
||||
// Number - pixel width of padding around tooltip text
|
||||
tooltipXPadding: 6,
|
||||
// Element defaults
|
||||
elements: {
|
||||
// Default settings for all line elements
|
||||
line: {
|
||||
// Number - Bezier curve tension. Set to 0 for no bezier curves
|
||||
tension: 0.4,
|
||||
|
||||
// Number - Size of the caret on the tooltip
|
||||
tooltipCaretSize: 8,
|
||||
// String - the fill color
|
||||
backgroundColor: defaultColor,
|
||||
|
||||
// Number - Pixel radius of the tooltip border
|
||||
tooltipCornerRadius: 6,
|
||||
// Number - width of the line
|
||||
borderWidth: 3,
|
||||
|
||||
// Number - Pixel offset from point x to tooltip edge
|
||||
tooltipXOffset: 10,
|
||||
{% raw %}
|
||||
// String - Template string for single tooltips
|
||||
tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= value %>",
|
||||
{% endraw %}
|
||||
// String - Template string for multiple tooltips
|
||||
multiTooltipTemplate: "<%= value %>",
|
||||
// String = color of the line
|
||||
borderColor: defaultColor,
|
||||
|
||||
// Boolean - if true fill in the area between the line and the x axis with the background color
|
||||
fill: true,
|
||||
|
||||
// Function - Will fire on animation progression.
|
||||
onAnimationProgress: function(){},
|
||||
// Boolean -
|
||||
skipNull: true,
|
||||
|
||||
// Function - Will fire on animation completion.
|
||||
onAnimationComplete: function(){}
|
||||
// Boolean -
|
||||
drawNull: false,
|
||||
},
|
||||
// Settings for all point elements
|
||||
point: {
|
||||
// Number - radius of point circle
|
||||
radius: 3,
|
||||
|
||||
// String - fill color of point
|
||||
backgroundColor: defaultColor,
|
||||
|
||||
// Number - width of stroke of point circle
|
||||
borderWidth: 1,
|
||||
|
||||
// String - stroke color for point
|
||||
borderColor: defaultColor,
|
||||
|
||||
// Number - extra radius added to radius for hit detection
|
||||
hitRadius: 6,
|
||||
|
||||
// Number - radius of point circle when hovered
|
||||
hoverRadius: 4,
|
||||
|
||||
// Number - radius of circle stroke when hovered
|
||||
hoverBorderWidth: 2,
|
||||
},
|
||||
// Settings for all bar elements
|
||||
bar: {
|
||||
// String - fill color of bar
|
||||
backgroundColor: defaultColor,
|
||||
|
||||
// Number - width of stroke of line surrounding bar fill
|
||||
borderWidth: 0,
|
||||
|
||||
// String - Border color
|
||||
borderColor: defaultColor,
|
||||
|
||||
// Number -
|
||||
valueSpacing: 5,
|
||||
|
||||
// Number -
|
||||
datasetSpacing: 1,
|
||||
},
|
||||
// Settings for all slice elements
|
||||
slice: {
|
||||
// String - fill color
|
||||
backgroundColor: defaultColor,
|
||||
|
||||
// String - border color
|
||||
borderColor: "#fff",
|
||||
|
||||
// Number - border stroke width
|
||||
borderWidth: 2,
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+189
-52
@@ -13,7 +13,10 @@ Often, it is used to show trend data, and the comparison of two data sets.
|
||||
|
||||
###Example usage
|
||||
```javascript
|
||||
var myLineChart = new Chart(ctx).Line(data, options);
|
||||
var myLineChart = new Chart(ctx).Line({
|
||||
data: data,
|
||||
options: options
|
||||
});
|
||||
```
|
||||
###Data structure
|
||||
|
||||
@@ -23,22 +26,57 @@ var data = {
|
||||
datasets: [
|
||||
{
|
||||
label: "My First dataset",
|
||||
fillColor: "rgba(220,220,220,0.2)",
|
||||
strokeColor: "rgba(220,220,220,1)",
|
||||
pointColor: "rgba(220,220,220,1)",
|
||||
pointStrokeColor: "#fff",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgba(220,220,220,1)",
|
||||
data: [65, 59, 80, 81, 56, 55, 40]
|
||||
|
||||
// Boolean - if true fill the area under the line
|
||||
fill: false,
|
||||
|
||||
// String - the color to fill the area under the line with if fill is true
|
||||
backgroundColor: "rgba(220,220,220,0.2)",
|
||||
|
||||
// The properties below allow an array to be specified to change the value of the item at the given index
|
||||
|
||||
// String or array - Line color
|
||||
borderColor: "rgba(220,220,220,1)",
|
||||
|
||||
// String or array - Point stroke color
|
||||
pointBorderColor: "rgba(220,220,220,1)",
|
||||
|
||||
// String or array - Point fill color
|
||||
pointBackgroundColor: "#fff",
|
||||
|
||||
// Number or array - Stroke width of point border
|
||||
pointBorderWidth: 1,
|
||||
|
||||
// Number or array - Radius of point when hovered
|
||||
pointHoverRadius: 5,
|
||||
|
||||
// String or array - point background color when hovered
|
||||
pointHoverBackgroundColor: "rgba(220,220,220,1)",
|
||||
|
||||
// Point border color when hovered
|
||||
pointHoverBorderColor: "rgba(220,220,220,1)",
|
||||
|
||||
// Number or array - border width of point when hovered
|
||||
pointBorderWidth: 2,
|
||||
|
||||
// The actual data
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
|
||||
// String - If specified, binds the dataset to a certain y-axis. If not specified, the first y-axis is used.
|
||||
yAxisID: "y-axis-1",
|
||||
},
|
||||
{
|
||||
label: "My Second dataset",
|
||||
fillColor: "rgba(151,187,205,0.2)",
|
||||
strokeColor: "rgba(151,187,205,1)",
|
||||
pointColor: "rgba(151,187,205,1)",
|
||||
pointStrokeColor: "#fff",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgba(151,187,205,1)",
|
||||
fill: false,
|
||||
backgroundColor: "rgba(220,220,220,0.2)",
|
||||
borderColor: "rgba(220,220,220,1)",
|
||||
pointBorderColor: "rgba(220,220,220,1)",
|
||||
pointBackgroundColor: "#fff",
|
||||
pointBorderWidth: 1,
|
||||
pointHoverRadius: 5,
|
||||
pointHoverBackgroundColor: "rgba(220,220,220,1)",
|
||||
pointHoverBorderColor: "rgba(220,220,220,1)",
|
||||
pointBorderWidth: 2,
|
||||
data: [28, 48, 40, 19, 86, 27, 90]
|
||||
}
|
||||
]
|
||||
@@ -56,65 +94,164 @@ These are the customisation options specific to Line charts. These options are m
|
||||
|
||||
```javascript
|
||||
{
|
||||
// Boolean - if true, line stack on top of each other along the y axis
|
||||
stacked: false,
|
||||
|
||||
///Boolean - Whether grid lines are shown across the chart
|
||||
scaleShowGridLines : true,
|
||||
hover: {
|
||||
// String - We use a label hover mode since the x axis displays data by the index in the dataset
|
||||
mode: "label"
|
||||
},
|
||||
|
||||
//String - Colour of the grid lines
|
||||
scaleGridLineColor : "rgba(0,0,0,.05)",
|
||||
scales: {
|
||||
// The line chart officially supports only 1 x-axis but uses an array to keep the API consistent. Use a scatter chart if you need multiple x axes.
|
||||
xAxes: [{
|
||||
// String - type of axis to use. Should not be changed from 'dataset'. To use a 'linear' axis on the x, use the scatter chart type
|
||||
scaleType: "dataset", // scatter should not use a dataset axis
|
||||
|
||||
//Number - Width of the grid lines
|
||||
scaleGridLineWidth : 1,
|
||||
// Boolean - if true, show the scale
|
||||
display: true,
|
||||
|
||||
//Boolean - Whether to show horizontal lines (except X axis)
|
||||
scaleShowHorizontalLines: true,
|
||||
// String - position of the scale. possible options are "top" and "bottom" for dataset scales
|
||||
position: "bottom",
|
||||
|
||||
//Boolean - Whether to show vertical lines (except Y axis)
|
||||
scaleShowVerticalLines: true,
|
||||
// String - id of the axis so that data can bind to it
|
||||
id: "x-axis-1", // need an ID so datasets can reference the scale
|
||||
|
||||
//Boolean - Whether the line is curved between points
|
||||
bezierCurve : true,
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
// Boolean - if true, show the grid lines
|
||||
show: true,
|
||||
|
||||
//Number - Tension of the bezier curve between points
|
||||
bezierCurveTension : 0.4,
|
||||
// String - color of the grid lines
|
||||
color: "rgba(0, 0, 0, 0.05)",
|
||||
|
||||
//Boolean - Whether to show a dot for each point
|
||||
pointDot : true,
|
||||
// Number - width of the grid lines
|
||||
lineWidth: 1,
|
||||
|
||||
//Number - Radius of each point dot in pixels
|
||||
pointDotRadius : 4,
|
||||
// Boolean - if true draw lines on the chart area
|
||||
drawOnChartArea: true,
|
||||
|
||||
//Number - Pixel width of point dot stroke
|
||||
pointDotStrokeWidth : 1,
|
||||
// Boolean - if true draw ticks in the axis area
|
||||
drawTicks: true,
|
||||
|
||||
//Number - amount extra to add to the radius to cater for hit detection outside the drawn point
|
||||
pointHitDetectionRadius : 20,
|
||||
// Number - width of the grid line for the first index (index 0)
|
||||
zeroLineWidth: 1,
|
||||
|
||||
//Boolean - Whether to show a stroke for datasets
|
||||
datasetStroke : true,
|
||||
// String - color of the grid line for the first index
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
|
||||
//Number - Pixel width of dataset stroke
|
||||
datasetStrokeWidth : 2,
|
||||
// Boolean - if true, offset labels from grid lines
|
||||
offsetGridLines: false,
|
||||
},
|
||||
|
||||
//Boolean - Whether to fill the dataset with a colour
|
||||
datasetFill : true,
|
||||
{% raw %}
|
||||
//String - A legend template
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
|
||||
{% endraw %}
|
||||
// label settings
|
||||
labels: {
|
||||
// Boolean - if true show labels
|
||||
show: true,
|
||||
|
||||
//Boolean - Whether to horizontally center the label and point dot inside the grid
|
||||
offsetGridLines : false
|
||||
// String - template string for labels
|
||||
template: "<%=value%>",
|
||||
|
||||
// Number - label font size
|
||||
fontSize: 12,
|
||||
|
||||
// String - label font style
|
||||
fontStyle: "normal",
|
||||
|
||||
// String - label font color
|
||||
fontColor: "#666",
|
||||
|
||||
// String - label font family
|
||||
fontFamily: "Helvetica Neue",
|
||||
},
|
||||
}],
|
||||
yAxes: [{
|
||||
// String - type of axis. 'linear' is the default but extensions may provide other types such as logarithmic
|
||||
scaleType: "linear",
|
||||
|
||||
// Boolean - if true, show the scale
|
||||
display: true,
|
||||
|
||||
// String - position of axis. Vertical axes can have either "left" or "right"
|
||||
position: "left",
|
||||
|
||||
// ID of the axis for data binding
|
||||
id: "y-axis-1",
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
// Boolean - if true, show the grid lines
|
||||
show: true,
|
||||
|
||||
// String - color of the grid lines
|
||||
color: "rgba(0, 0, 0, 0.05)",
|
||||
|
||||
// Number - width of the grid lines
|
||||
lineWidth: 1,
|
||||
|
||||
// Boolean - if true draw lines on the chart area
|
||||
drawOnChartArea: true,
|
||||
|
||||
// Boolean - if true draw ticks in the axis area
|
||||
drawTicks: true,
|
||||
|
||||
// Number - width of the grid line representing a numerical value of 0
|
||||
zeroLineWidth: 1,
|
||||
|
||||
// String - color of the grid line representing a numerical value of 0
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
},
|
||||
|
||||
// Boolean - if true ensures that the scale always has a 0 point
|
||||
beginAtZero: false,
|
||||
|
||||
// Object - if specified, allows the user to override the step generation algorithm.
|
||||
// Contains the following values
|
||||
// start: // number to start at
|
||||
// stepWidth: // size of step
|
||||
// steps: // number of steps
|
||||
override: null,
|
||||
|
||||
// label settings
|
||||
labels: {
|
||||
// Boolean - if true show labels
|
||||
show: true,
|
||||
|
||||
// String - template string for labels
|
||||
template: "<%=value%>",
|
||||
|
||||
// Function - if specified this is passed the tick value, index, and the array of all tick values. Returns a string that is used as the label for that value
|
||||
userCallback: null,
|
||||
|
||||
// Number - label font size
|
||||
fontSize: 12,
|
||||
|
||||
// String - label font style
|
||||
fontStyle: "normal",
|
||||
|
||||
// String - label font color
|
||||
fontColor: "#666",
|
||||
|
||||
// String - label font family
|
||||
fontFamily: "Helvetica Neue",
|
||||
},
|
||||
}],
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
You can override these for your `Chart` instance by passing a second argument into the `Line` method as an object with the keys you want to override.
|
||||
You can override these for your `Chart` instance by passing a member `options` into the `Line` method.
|
||||
|
||||
For example, we could have a line chart without bezier curves between points by doing the following:
|
||||
For example, we could have a line chart display without an x axis by doing the following. The config merge is smart enough to handle arrays so that you do not need to specify all axis settings to change one thing.
|
||||
|
||||
```javascript
|
||||
new Chart(ctx).Line(data, {
|
||||
bezierCurve: false
|
||||
new Chart(ctx).Line({
|
||||
data: data,
|
||||
options: {
|
||||
xAxes: [{
|
||||
show: false
|
||||
}]
|
||||
}
|
||||
});
|
||||
// This will create a chart with all of the default options, merged from the global config,
|
||||
// and the Line chart defaults, but this particular instance will have `bezierCurve` set to false.
|
||||
|
||||
+171
-37
@@ -14,7 +14,10 @@ It is sometimes used to show trend data, and the comparison of multiple data set
|
||||
|
||||
### Example usage
|
||||
```javascript
|
||||
var myBarChart = new Chart(ctx).Bar(data, options);
|
||||
var myBarChart = new Chart(ctx).Bar({
|
||||
data: data,
|
||||
options: options
|
||||
});
|
||||
```
|
||||
|
||||
### Data structure
|
||||
@@ -25,18 +28,36 @@ var data = {
|
||||
datasets: [
|
||||
{
|
||||
label: "My First dataset",
|
||||
fillColor: "rgba(220,220,220,0.5)",
|
||||
strokeColor: "rgba(220,220,220,0.8)",
|
||||
highlightFill: "rgba(220,220,220,0.75)",
|
||||
highlightStroke: "rgba(220,220,220,1)",
|
||||
data: [65, 59, 80, 81, 56, 55, 40]
|
||||
|
||||
// The properties below allow an array to be specified to change the value of the item at the given index
|
||||
// String or array - the bar color
|
||||
backgroundColor: "rgba(220,220,220,0.2)",
|
||||
|
||||
// String or array - bar stroke color
|
||||
borderColor: "rgba(220,220,220,1)",
|
||||
|
||||
// Number or array - bar border width
|
||||
borderWidth: 1,
|
||||
|
||||
// String or array - fill color when hovered
|
||||
hoverBackgroundColor: "rgba(220,220,220,0.2)",
|
||||
|
||||
// String or array - border color when hovered
|
||||
hoverBorderColor: "rgba(220,220,220,1)",
|
||||
|
||||
// The actual data
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
|
||||
// String - If specified, binds the dataset to a certain y-axis. If not specified, the first y-axis is used.
|
||||
yAxisID: "y-axis-1",
|
||||
},
|
||||
{
|
||||
label: "My Second dataset",
|
||||
fillColor: "rgba(151,187,205,0.5)",
|
||||
strokeColor: "rgba(151,187,205,0.8)",
|
||||
highlightFill: "rgba(151,187,205,0.75)",
|
||||
highlightStroke: "rgba(151,187,205,1)",
|
||||
backgroundColor: "rgba(220,220,220,0.2)",
|
||||
borderColor: "rgba(220,220,220,1)",
|
||||
borderWidth: 1,
|
||||
hoverBackgroundColor: "rgba(220,220,220,0.2)",
|
||||
hoverBorderColor: "rgba(220,220,220,1)",
|
||||
data: [28, 48, 40, 19, 86, 27, 90]
|
||||
}
|
||||
]
|
||||
@@ -53,40 +74,150 @@ These are the customisation options specific to Bar charts. These options are me
|
||||
|
||||
```javascript
|
||||
{
|
||||
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
|
||||
scaleBeginAtZero : true,
|
||||
// Boolean - if true, bars stack on top of each other
|
||||
stacked: false,
|
||||
|
||||
//Boolean - Whether grid lines are shown across the chart
|
||||
scaleShowGridLines : true,
|
||||
hover: {
|
||||
// String - We use a label hover mode since the x axis displays data by the index in the dataset
|
||||
mode: "label"
|
||||
},
|
||||
|
||||
//String - Colour of the grid lines
|
||||
scaleGridLineColor : "rgba(0,0,0,.05)",
|
||||
scales: {
|
||||
// The bar chart officially supports only 1 x-axis but uses an array to keep the API consistent. Use a scatter chart if you need multiple x axes.
|
||||
xAxes: [{
|
||||
// String - type of axis to use. Should not be changed from 'dataset'.
|
||||
scaleType: "dataset", // scatter should not use a dataset axis
|
||||
|
||||
//Number - Width of the grid lines
|
||||
scaleGridLineWidth : 1,
|
||||
// Boolean - if true, show the scale
|
||||
display: true,
|
||||
|
||||
//Boolean - Whether to show horizontal lines (except X axis)
|
||||
scaleShowHorizontalLines: true,
|
||||
// String - position of the scale. possible options are "top" and "bottom" for dataset scales
|
||||
position: "bottom",
|
||||
|
||||
//Boolean - Whether to show vertical lines (except Y axis)
|
||||
scaleShowVerticalLines: true,
|
||||
// String - id of the axis so that data can bind to it
|
||||
id: "x-axis-1", // need an ID so datasets can reference the scale
|
||||
|
||||
//Boolean - If there is a stroke on each bar
|
||||
barShowStroke : true,
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
// Boolean - if true, show the grid lines
|
||||
show: true,
|
||||
|
||||
//Number - Pixel width of the bar stroke
|
||||
barStrokeWidth : 2,
|
||||
// String - color of the grid lines
|
||||
color: "rgba(0, 0, 0, 0.05)",
|
||||
|
||||
//Number - Spacing between each of the X value sets
|
||||
barValueSpacing : 5,
|
||||
// Number - width of the grid lines
|
||||
lineWidth: 1,
|
||||
|
||||
//Number - Spacing between data sets within X values
|
||||
barDatasetSpacing : 1,
|
||||
{% raw %}
|
||||
//String - A legend template
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
|
||||
{% endraw %}
|
||||
}
|
||||
// Boolean - if true draw lines on the chart area
|
||||
drawOnChartArea: true,
|
||||
|
||||
// Boolean - if true draw ticks in the axis area
|
||||
drawTicks: true,
|
||||
|
||||
// Number - width of the grid line for the first index (index 0)
|
||||
zeroLineWidth: 1,
|
||||
|
||||
// String - color of the grid line for the first index
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
|
||||
// Boolean - if true, offset labels from grid lines
|
||||
offsetGridLines: false,
|
||||
},
|
||||
|
||||
// label settings
|
||||
labels: {
|
||||
// Boolean - if true show labels
|
||||
show: true,
|
||||
|
||||
// String - template string for labels
|
||||
template: "<%=value%>",
|
||||
|
||||
// Number - label font size
|
||||
fontSize: 12,
|
||||
|
||||
// String - label font style
|
||||
fontStyle: "normal",
|
||||
|
||||
// String - label font color
|
||||
fontColor: "#666",
|
||||
|
||||
// String - label font family
|
||||
fontFamily: "Helvetica Neue",
|
||||
},
|
||||
}],
|
||||
yAxes: [{
|
||||
// String - type of axis. 'linear' is the default but extensions may provide other types such as logarithmic
|
||||
scaleType: "linear",
|
||||
|
||||
// Boolean - if true, show the scale
|
||||
display: true,
|
||||
|
||||
// String - position of axis. Vertical axes can have either "left" or "right"
|
||||
position: "left",
|
||||
|
||||
// ID of the axis for data binding
|
||||
id: "y-axis-1",
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
// Boolean - if true, show the grid lines
|
||||
show: true,
|
||||
|
||||
// String - color of the grid lines
|
||||
color: "rgba(0, 0, 0, 0.05)",
|
||||
|
||||
// Number - width of the grid lines
|
||||
lineWidth: 1,
|
||||
|
||||
// Boolean - if true draw lines on the chart area
|
||||
drawOnChartArea: true,
|
||||
|
||||
// Boolean - if true draw ticks in the axis area
|
||||
drawTicks: true,
|
||||
|
||||
// Number - width of the grid line representing a numerical value of 0
|
||||
zeroLineWidth: 1,
|
||||
|
||||
// String - color of the grid line representing a numerical value of 0
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
},
|
||||
|
||||
// Boolean - if true ensures that the scale always has a 0 point
|
||||
beginAtZero: false,
|
||||
|
||||
// Object - if specified, allows the user to override the step generation algorithm.
|
||||
// Contains the following values
|
||||
// start: // number to start at
|
||||
// stepWidth: // size of step
|
||||
// steps: // number of steps
|
||||
override: null,
|
||||
|
||||
// label settings
|
||||
labels: {
|
||||
// Boolean - if true show labels
|
||||
show: true,
|
||||
|
||||
// String - template string for labels
|
||||
template: "<%=value%>",
|
||||
|
||||
// Function - if specified this is passed the tick value, index, and the array of all tick values. Returns a string that is used as the label for that value
|
||||
userCallback: null,
|
||||
|
||||
// Number - label font size
|
||||
fontSize: 12,
|
||||
|
||||
// String - label font style
|
||||
fontStyle: "normal",
|
||||
|
||||
// String - label font color
|
||||
fontColor: "#666",
|
||||
|
||||
// String - label font family
|
||||
fontFamily: "Helvetica Neue",
|
||||
},
|
||||
}],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
You can override these for your `Chart` instance by passing a second argument into the `Bar` method as an object with the keys you want to override.
|
||||
@@ -94,8 +225,11 @@ You can override these for your `Chart` instance by passing a second argument in
|
||||
For example, we could have a bar chart without a stroke on each bar by doing the following:
|
||||
|
||||
```javascript
|
||||
new Chart(ctx).Bar(data, {
|
||||
barShowStroke: false
|
||||
new Chart(ctx).Bar({
|
||||
data: data,
|
||||
options: {
|
||||
barShowStroke: false
|
||||
}
|
||||
});
|
||||
// This will create a chart with all of the default options, merged from the global config,
|
||||
// and the Bar chart defaults but this particular instance will have `barShowStroke` set to false.
|
||||
|
||||
+88
-88
@@ -1,18 +1,18 @@
|
||||
var gulp = require('gulp'),
|
||||
concat = require('gulp-concat'),
|
||||
uglify = require('gulp-uglify'),
|
||||
util = require('gulp-util'),
|
||||
jshint = require('gulp-jshint'),
|
||||
size = require('gulp-size'),
|
||||
connect = require('gulp-connect'),
|
||||
replace = require('gulp-replace'),
|
||||
htmlv = require('gulp-html-validator'),
|
||||
inquirer = require('inquirer'),
|
||||
semver = require('semver'),
|
||||
exec = require('child_process').exec,
|
||||
fs = require('fs'),
|
||||
package = require('./package.json'),
|
||||
bower = require('./bower.json');
|
||||
concat = require('gulp-concat'),
|
||||
uglify = require('gulp-uglify'),
|
||||
util = require('gulp-util'),
|
||||
jshint = require('gulp-jshint'),
|
||||
size = require('gulp-size'),
|
||||
connect = require('gulp-connect'),
|
||||
replace = require('gulp-replace'),
|
||||
htmlv = require('gulp-html-validator'),
|
||||
inquirer = require('inquirer'),
|
||||
semver = require('semver'),
|
||||
exec = require('child_process').exec,
|
||||
fs = require('fs'),
|
||||
package = require('./package.json'),
|
||||
bower = require('./bower.json');
|
||||
|
||||
var srcDir = './src/';
|
||||
/*
|
||||
@@ -21,32 +21,30 @@ var srcDir = './src/';
|
||||
* - A minified version of this code, in Chart.min.js
|
||||
*/
|
||||
|
||||
gulp.task('build', function(){
|
||||
gulp.task('build', function() {
|
||||
|
||||
// Default to all of the chart types, with Chart.Core first
|
||||
var srcFiles = [FileName('Core')],
|
||||
isCustom = !!(util.env.types),
|
||||
outputDir = (isCustom) ? 'custom' : '.';
|
||||
if (isCustom){
|
||||
util.env.types.split(',').forEach(function(type){ return srcFiles.push(FileName(type));});
|
||||
}
|
||||
else{
|
||||
// Seems gulp-concat remove duplicates - nice!
|
||||
// So we can use this to sort out dependency order - aka include Core first!
|
||||
srcFiles.push(srcDir+'*');
|
||||
}
|
||||
var srcFiles = [
|
||||
'./src/core/core.js',
|
||||
'./src/core/**',
|
||||
'./src/scales/**',
|
||||
'./src/elements/**',
|
||||
'./src/charts/**',
|
||||
'./src/**',
|
||||
'./node_modules/color/dist/color.min.js'
|
||||
],
|
||||
isCustom = !!(util.env.types),
|
||||
outputDir = (isCustom) ? 'custom' : '.';
|
||||
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(concat('Chart.js'))
|
||||
.pipe(replace('{{ version }}', package.version))
|
||||
.pipe(gulp.dest(outputDir))
|
||||
.pipe(uglify({preserveComments:'some'}))
|
||||
.pipe(concat('Chart.min.js'))
|
||||
.pipe(gulp.dest(outputDir));
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(concat('Chart.js'))
|
||||
.pipe(replace('{{ version }}', package.version))
|
||||
.pipe(gulp.dest(outputDir))
|
||||
.pipe(uglify({
|
||||
preserveComments: 'some'
|
||||
}))
|
||||
.pipe(concat('Chart.min.js'))
|
||||
.pipe(gulp.dest(outputDir));
|
||||
|
||||
function FileName(moduleName){
|
||||
return srcDir+'Chart.'+moduleName+'.js';
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
@@ -55,65 +53,67 @@ gulp.task('build', function(){
|
||||
* Output: - New version number written into package.json & bower.json
|
||||
*/
|
||||
|
||||
gulp.task('bump', function(complete){
|
||||
util.log('Current version:', util.colors.cyan(package.version));
|
||||
var choices = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'].map(function(versionType){
|
||||
return versionType + ' (v' + semver.inc(package.version, versionType) + ')';
|
||||
});
|
||||
inquirer.prompt({
|
||||
type: 'list',
|
||||
name: 'version',
|
||||
message: 'What version update would you like?',
|
||||
choices: choices
|
||||
}, function(res){
|
||||
var increment = res.version.split(' ')[0],
|
||||
newVersion = semver.inc(package.version, increment);
|
||||
gulp.task('bump', function(complete) {
|
||||
util.log('Current version:', util.colors.cyan(package.version));
|
||||
var choices = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'].map(function(versionType) {
|
||||
return versionType + ' (v' + semver.inc(package.version, versionType) + ')';
|
||||
});
|
||||
inquirer.prompt({
|
||||
type: 'list',
|
||||
name: 'version',
|
||||
message: 'What version update would you like?',
|
||||
choices: choices
|
||||
}, function(res) {
|
||||
var increment = res.version.split(' ')[0],
|
||||
newVersion = semver.inc(package.version, increment);
|
||||
|
||||
// Set the new versions into the bower/package object
|
||||
package.version = newVersion;
|
||||
bower.version = newVersion;
|
||||
// Set the new versions into the bower/package object
|
||||
package.version = newVersion;
|
||||
bower.version = newVersion;
|
||||
|
||||
// Write these to their own files, then build the output
|
||||
fs.writeFileSync('package.json', JSON.stringify(package, null, 2));
|
||||
fs.writeFileSync('bower.json', JSON.stringify(bower, null, 2));
|
||||
// Write these to their own files, then build the output
|
||||
fs.writeFileSync('package.json', JSON.stringify(package, null, 2));
|
||||
fs.writeFileSync('bower.json', JSON.stringify(bower, null, 2));
|
||||
|
||||
complete();
|
||||
});
|
||||
complete();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('release', ['build'], function(){
|
||||
exec('git tag -a v' + package.version);
|
||||
gulp.task('release', ['build'], function() {
|
||||
exec('git tag -a v' + package.version);
|
||||
});
|
||||
|
||||
gulp.task('jshint', function(){
|
||||
return gulp.src(srcDir + '*.js')
|
||||
.pipe(jshint())
|
||||
.pipe(jshint.reporter('default'));
|
||||
gulp.task('jshint', function() {
|
||||
return gulp.src(srcDir + '*.js')
|
||||
.pipe(jshint())
|
||||
.pipe(jshint.reporter('default'));
|
||||
});
|
||||
|
||||
gulp.task('valid', function(){
|
||||
return gulp.src('samples/*.html')
|
||||
.pipe(htmlv());
|
||||
gulp.task('valid', function() {
|
||||
return gulp.src('samples/*.html')
|
||||
.pipe(htmlv());
|
||||
});
|
||||
|
||||
gulp.task('library-size', function(){
|
||||
return gulp.src('Chart.min.js')
|
||||
.pipe(size({
|
||||
gzip: true
|
||||
}));
|
||||
gulp.task('library-size', function() {
|
||||
return gulp.src('Chart.min.js')
|
||||
.pipe(size({
|
||||
gzip: true
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('module-sizes', function(){
|
||||
return gulp.src(srcDir + '*.js')
|
||||
.pipe(uglify({preserveComments:'some'}))
|
||||
.pipe(size({
|
||||
showFiles: true,
|
||||
gzip: true
|
||||
}));
|
||||
gulp.task('module-sizes', function() {
|
||||
return gulp.src(srcDir + '*.js')
|
||||
.pipe(uglify({
|
||||
preserveComments: 'some'
|
||||
}))
|
||||
.pipe(size({
|
||||
showFiles: true,
|
||||
gzip: true
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('watch', function(){
|
||||
gulp.watch('./src/*', ['build']);
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch('./src/**', ['build']);
|
||||
});
|
||||
|
||||
gulp.task('test', ['jshint', 'valid']);
|
||||
@@ -122,16 +122,16 @@ gulp.task('size', ['library-size', 'module-sizes']);
|
||||
|
||||
gulp.task('default', ['build', 'watch']);
|
||||
|
||||
gulp.task('server', function(){
|
||||
connect.server({
|
||||
port: 8000
|
||||
});
|
||||
gulp.task('server', function() {
|
||||
connect.server({
|
||||
port: 8000
|
||||
});
|
||||
});
|
||||
|
||||
// Convenience task for opening the project straight from the command line
|
||||
gulp.task('_open', function(){
|
||||
exec('open http://localhost:8000');
|
||||
exec('subl .');
|
||||
gulp.task('_open', function() {
|
||||
exec('open http://localhost:8000');
|
||||
exec('subl .');
|
||||
});
|
||||
|
||||
gulp.task('dev', ['server', 'default']);
|
||||
|
||||
+30
-27
@@ -1,28 +1,31 @@
|
||||
{
|
||||
"name": "chart.js",
|
||||
"homepage": "http://www.chartjs.org",
|
||||
"description": "Simple HTML5 charts using the canvas element.",
|
||||
"version": "1.0.2",
|
||||
"main": "Chart.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nnnick/Chart.js.git"
|
||||
},
|
||||
"dependences": {},
|
||||
"devDependencies": {
|
||||
"gulp": "3.5.x",
|
||||
"gulp-concat": "~2.1.x",
|
||||
"gulp-connect": "~2.0.5",
|
||||
"gulp-jshint": "~1.5.1",
|
||||
"gulp-replace": "^0.4.0",
|
||||
"gulp-size": "~0.4.0",
|
||||
"gulp-uglify": "~0.2.x",
|
||||
"gulp-util": "~2.2.x",
|
||||
"gulp-html-validator": "^0.0.2",
|
||||
"inquirer": "^0.5.1",
|
||||
"semver": "^3.0.1"
|
||||
},
|
||||
"spm": {
|
||||
"main": "Chart.js"
|
||||
}
|
||||
}
|
||||
"name": "chart.js",
|
||||
"homepage": "http://www.chartjs.org",
|
||||
"description": "Simple HTML5 charts using the canvas element.",
|
||||
"version": "2.0.0-alpha",
|
||||
"main": "Chart.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nnnick/Chart.js.git"
|
||||
},
|
||||
"dependences": {},
|
||||
"devDependencies": {
|
||||
"color": "git://github.com/chartjs/color",
|
||||
"gulp": "3.5.x",
|
||||
"gulp-concat": "~2.1.x",
|
||||
"gulp-connect": "~2.0.5",
|
||||
"gulp-html-validator": "^0.0.2",
|
||||
"gulp-jshint": "~1.5.1",
|
||||
"gulp-replace": "^0.4.0",
|
||||
"gulp-size": "~0.4.0",
|
||||
"gulp-uglify": "~0.2.x",
|
||||
"gulp-util": "~2.2.x",
|
||||
"inquirer": "^0.5.1",
|
||||
"jquery": "^2.1.4",
|
||||
"onecolor": "^2.5.0",
|
||||
"semver": "^3.0.1"
|
||||
},
|
||||
"spm": {
|
||||
"main": "Chart.js"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Bar Chart Multi Axis</title>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width: 50%">
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
var randomColor = function() {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
};
|
||||
|
||||
var barChartData = {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: 'Dataset 1',
|
||||
backgroundColor: "rgba(220,220,220,0.5)",
|
||||
yAxisID: "y-axis-1",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: 'Dataset 2',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
yAxisID: "y-axis-2",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: 'Dataset 3',
|
||||
backgroundColor: [randomColor(), randomColor(), randomColor(), randomColor(), randomColor(), randomColor(), randomColor()],
|
||||
yAxisID: "y-axis-1",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}]
|
||||
|
||||
};
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myBar = new Chart(ctx).Bar({
|
||||
data: barChartData,
|
||||
options: {
|
||||
responsive: true,
|
||||
hoverMode: 'label',
|
||||
hoverAnimationDuration: 400,
|
||||
stacked: false,
|
||||
scales: {
|
||||
yAxes: [{
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
display: true,
|
||||
position: "left",
|
||||
id: "y-axis-1",
|
||||
}, {
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
display: true,
|
||||
position: "right",
|
||||
id: "y-axis-2",
|
||||
gridLines: {
|
||||
drawOnChartArea: false
|
||||
}
|
||||
}],
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(barChartData.datasets, function(i, dataset) {
|
||||
if (Chart.helpers.isArray(dataset.backgroundColor)) {
|
||||
dataset.backgroundColor= [randomColor(), randomColor(), randomColor(), randomColor(), randomColor(), randomColor(), randomColor()];
|
||||
} else {
|
||||
dataset.backgroundColor= randomColor();
|
||||
}
|
||||
|
||||
dataset.data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
});
|
||||
window.myBar.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,69 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Stacked Bar Chart</title>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width: 50%">
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
|
||||
var barChartData = {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: 'Dataset 1',
|
||||
backgroundColor: "rgba(220,220,220,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: 'Dataset 2',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: 'Dataset 3',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}]
|
||||
|
||||
};
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myBar = new Chart(ctx).Bar({
|
||||
data: barChartData,
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
stacked: true,
|
||||
}],
|
||||
yAxes: [{
|
||||
stacked: true
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(barChartData.datasets, function(i, dataset) {
|
||||
dataset.backgroundColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
dataset.data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
});
|
||||
window.myBar.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+50
-46
@@ -1,57 +1,61 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bar Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 50%">
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
|
||||
<script>
|
||||
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
|
||||
var randomColorFactor = function(){ return Math.round(Math.random()*255)};
|
||||
<head>
|
||||
<title>Bar Chart</title>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
</head>
|
||||
|
||||
var barChartData = {
|
||||
labels : ["January","February","March","April","May","June","July"],
|
||||
datasets : [
|
||||
{
|
||||
fillColor : "rgba(220,220,220,0.5)",
|
||||
strokeColor : "rgba(220,220,220,0.8)",
|
||||
highlightFill: "rgba(220,220,220,0.75)",
|
||||
highlightStroke: "rgba(220,220,220,1)",
|
||||
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
|
||||
},
|
||||
{
|
||||
fillColor : "rgba(151,187,205,0.5)",
|
||||
strokeColor : "rgba(151,187,205,0.8)",
|
||||
highlightFill : "rgba(151,187,205,0.75)",
|
||||
highlightStroke : "rgba(151,187,205,1)",
|
||||
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
|
||||
}
|
||||
]
|
||||
<body>
|
||||
<div style="width: 50%">
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
|
||||
}
|
||||
window.onload = function(){
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myBar = new Chart(ctx).Bar(barChartData, {
|
||||
responsive : true
|
||||
});
|
||||
}
|
||||
var barChartData = {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: 'Dataset 1',
|
||||
backgroundColor: "rgba(220,220,220,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: 'Dataset 2',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: 'Dataset 3',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}]
|
||||
|
||||
$('#randomizeData').click(function(){
|
||||
barChartData.datasets[0].fillColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
barChartData.datasets[0].data = [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()];
|
||||
};
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myBar = new Chart(ctx).Bar({
|
||||
data: barChartData,
|
||||
options: {
|
||||
responsive: true,
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
barChartData.datasets[1].fillColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
barChartData.datasets[1].data = [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()];
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(barChartData.datasets, function(i, dataset) {
|
||||
dataset.backgroundColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
dataset.data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
window.myBar.update();
|
||||
});
|
||||
window.myBar.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -48,7 +48,12 @@
|
||||
|
||||
window.onload = function(){
|
||||
var ctx = document.getElementById("chart-area").getContext("2d");
|
||||
window.myDoughnut = new Chart(ctx).Doughnut(doughnutData, {responsive : true});
|
||||
window.myDoughnut = new Chart(ctx).Doughnut({
|
||||
data: doughnutData,
|
||||
options: {
|
||||
responsive : true
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
+101
-71
@@ -1,80 +1,110 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Doughnut Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
body{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#canvas-holder{
|
||||
width:30%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="canvas-holder">
|
||||
<canvas id="chart-area" width="500" height="500"/>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
|
||||
<head>
|
||||
<title>Doughnut Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#canvas-holder {
|
||||
width: 30%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<script>
|
||||
<body>
|
||||
<div id="canvas-holder" style="width:100%">
|
||||
<canvas id="chart-area" width="500" height="500" />
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
|
||||
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
|
||||
var randomColorFactor = function(){ return Math.round(Math.random()*255)};
|
||||
var config = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
],
|
||||
backgroundColor: [
|
||||
"#F7464A",
|
||||
"#46BFBD",
|
||||
"#FDB45C",
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
}, {
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
],
|
||||
backgroundColor: [
|
||||
"#F7464A",
|
||||
"#46BFBD",
|
||||
"#FDB45C",
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
}, {
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
],
|
||||
backgroundColor: [
|
||||
"#F7464A",
|
||||
"#46BFBD",
|
||||
"#FDB45C",
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
}],
|
||||
labels: [
|
||||
"Red",
|
||||
"Green",
|
||||
"Yellow",
|
||||
"Grey",
|
||||
"Dark Grey"
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true
|
||||
}
|
||||
};
|
||||
|
||||
var doughnutData = [
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color:"#F7464A",
|
||||
highlight: "#FF5A5E",
|
||||
label: "Red"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#46BFBD",
|
||||
highlight: "#5AD3D1",
|
||||
label: "Green"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#FDB45C",
|
||||
highlight: "#FFC870",
|
||||
label: "Yellow"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#949FB1",
|
||||
highlight: "#A8B3C5",
|
||||
label: "Grey"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#4D5360",
|
||||
highlight: "#616774",
|
||||
label: "Dark Grey"
|
||||
}
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("chart-area").getContext("2d");
|
||||
window.myDoughnut = new Chart(ctx).Doughnut(config);
|
||||
};
|
||||
|
||||
];
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, piece) {
|
||||
$.each(piece.data, function(j, value) {
|
||||
config.data.datasets[i].data[j] = randomScalingFactor();
|
||||
});
|
||||
});
|
||||
window.myDoughnut.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
window.onload = function(){
|
||||
var ctx = document.getElementById("chart-area").getContext("2d");
|
||||
window.myDoughnut = new Chart(ctx).Doughnut(doughnutData, {responsive : true});
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function(){
|
||||
$.each(doughnutData, function(i, piece){
|
||||
doughnutData[i].value = randomScalingFactor();
|
||||
doughnutData[i].color = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
});
|
||||
window.myDoughnut.update();
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -112,10 +112,13 @@
|
||||
|
||||
window.onload = function() {
|
||||
var ctx1 = document.getElementById("chart1").getContext("2d");
|
||||
window.myLine = new Chart(ctx1).Line(lineChartData, {
|
||||
showScale: false,
|
||||
pointDot : true,
|
||||
responsive: true
|
||||
window.myLine = new Chart(ctx1).Line({
|
||||
data: lineChartData,
|
||||
options: {
|
||||
showScale: false,
|
||||
pointDot : true,
|
||||
responsive: true
|
||||
}
|
||||
});
|
||||
|
||||
var ctx2 = document.getElementById("chart2").getContext("2d");
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Line Chart Multiple Axes</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
|
||||
var lineChartData = {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
yAxisID: "y-axis-1",
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
yAxisID: "y-axis-2"
|
||||
}]
|
||||
};
|
||||
|
||||
$.each(lineChartData.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(1);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(lineChartData);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx).Line({
|
||||
data: lineChartData,
|
||||
options: {
|
||||
responsive: true,
|
||||
hoverMode: 'label',
|
||||
stacked: false,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true,
|
||||
gridLines: {
|
||||
offsetGridLines: false
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
display: true,
|
||||
position: "left",
|
||||
id: "y-axis-1",
|
||||
}, {
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
display: true,
|
||||
position: "right",
|
||||
id: "y-axis-2",
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
drawOnChartArea: false, // only want the grid lines for one axis to show up
|
||||
},
|
||||
}],
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
lineChartData.datasets[0].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
lineChartData.datasets[1].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+70
-58
@@ -1,68 +1,80 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:30%">
|
||||
<div>
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<script>
|
||||
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
|
||||
var randomColorFactor = function(){ return Math.round(Math.random()*255)};
|
||||
<body>
|
||||
<div style="width:50%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
|
||||
var lineChartData = {
|
||||
labels : ["January","February","March","April","May","June","July"],
|
||||
datasets : [
|
||||
{
|
||||
label: "My First dataset",
|
||||
fillColor : "rgba(220,220,220,0.2)",
|
||||
strokeColor : "rgba(220,220,220,1)",
|
||||
pointColor : "rgba(220,220,220,1)",
|
||||
pointStrokeColor : "#fff",
|
||||
pointHighlightFill : "#fff",
|
||||
pointHighlightStroke : "rgba(220,220,220,1)",
|
||||
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
|
||||
},
|
||||
{
|
||||
label: "My Second dataset",
|
||||
fillColor : "rgba(151,187,205,0.2)",
|
||||
strokeColor : "rgba(151,187,205,1)",
|
||||
pointColor : "rgba(151,187,205,1)",
|
||||
pointStrokeColor : "#fff",
|
||||
pointHighlightFill : "#fff",
|
||||
pointHighlightStroke : "rgba(151,187,205,1)",
|
||||
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
|
||||
}
|
||||
]
|
||||
var config = {
|
||||
data: {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
fill: false,
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true
|
||||
}],
|
||||
yAxes: [{
|
||||
display: true
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
window.onload = function(){
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx).Line(lineChartData, {
|
||||
responsive: true
|
||||
});
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function(){
|
||||
lineChartData.datasets[0].fillColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.3)';
|
||||
lineChartData.datasets[0].data = [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()];
|
||||
|
||||
lineChartData.datasets[1].fillColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.3)';
|
||||
lineChartData.datasets[1].data = [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()];
|
||||
|
||||
window.myLine.update();
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx).Line(config);
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
config.data.datasets[0].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
config.data.datasets[1].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -145,10 +145,14 @@
|
||||
|
||||
window.onload = function() {
|
||||
var ctx1 = document.getElementById("chart-area1").getContext("2d");
|
||||
window.myPie = new Chart(ctx1).Pie(pieData);
|
||||
window.myPie = new Chart(ctx1).Pie({
|
||||
data: pieData
|
||||
});
|
||||
|
||||
var ctx2 = document.getElementById("chart-area2").getContext("2d");
|
||||
window.myPie = new Chart(ctx2).Pie(pieData);
|
||||
window.myPie = new Chart(ctx2).Pie({
|
||||
data: pieData
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
||||
+92
-61
@@ -1,70 +1,101 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Pie Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="canvas-holder">
|
||||
<canvas id="chart-area" width="300" height="300"/>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
|
||||
<script>
|
||||
<head>
|
||||
<title>Pie Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
|
||||
var randomColorFactor = function(){ return Math.round(Math.random()*255)};
|
||||
<body>
|
||||
<div id="canvas-holder">
|
||||
<canvas id="chart-area" width="300" height="300" />
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
|
||||
var pieData = [
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color:"#F7464A",
|
||||
highlight: "#FF5A5E",
|
||||
label: "Red"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#46BFBD",
|
||||
highlight: "#5AD3D1",
|
||||
label: "Green"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#FDB45C",
|
||||
highlight: "#FFC870",
|
||||
label: "Yellow"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#949FB1",
|
||||
highlight: "#A8B3C5",
|
||||
label: "Grey"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#4D5360",
|
||||
highlight: "#616774",
|
||||
label: "Dark Grey"
|
||||
}
|
||||
var config = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
],
|
||||
backgroundColor: [
|
||||
"#F7464A",
|
||||
"#46BFBD",
|
||||
"#FDB45C",
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
}, {
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
],
|
||||
backgroundColor: [
|
||||
"#F7464A",
|
||||
"#46BFBD",
|
||||
"#FDB45C",
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
}, {
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
],
|
||||
backgroundColor: [
|
||||
"#F7464A",
|
||||
"#46BFBD",
|
||||
"#FDB45C",
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
}],
|
||||
labels: [
|
||||
"Red",
|
||||
"Green",
|
||||
"Yellow",
|
||||
"Grey",
|
||||
"Dark Grey"
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true
|
||||
}
|
||||
};
|
||||
|
||||
];
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("chart-area").getContext("2d");
|
||||
window.myPie = new Chart(ctx).Pie(config);
|
||||
};
|
||||
|
||||
window.onload = function(){
|
||||
var ctx = document.getElementById("chart-area").getContext("2d");
|
||||
window.myPie = new Chart(ctx).Pie(pieData);
|
||||
};
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, piece) {
|
||||
$.each(piece.data, function(j, value) {
|
||||
config.data.datasets[i].data[j] = randomScalingFactor();
|
||||
//config.data.datasets.backgroundColor[i] = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
});
|
||||
});
|
||||
window.myPie.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
$('#randomizeData').click(function(){
|
||||
$.each(pieData, function(i, piece){
|
||||
pieData[i].value = randomScalingFactor();
|
||||
pieData[i].color = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
});
|
||||
window.myPie.update();
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+62
-64
@@ -1,73 +1,71 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Polar Area Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="canvas-holder" style="width:30%">
|
||||
<canvas id="chart-area" width="300" height="300"/>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
|
||||
<head>
|
||||
<title>Polar Area Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<script>
|
||||
<body>
|
||||
<div id="canvas-holder" style="width:100%">
|
||||
<canvas id="chart-area" width="300" height="300" />
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
|
||||
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
|
||||
var randomColorFactor = function(){ return Math.round(Math.random()*255)};
|
||||
var config = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
],
|
||||
backgroundColor: [
|
||||
"#F7464A",
|
||||
"#46BFBD",
|
||||
"#FDB45C",
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
labels: [
|
||||
"Red",
|
||||
"Green",
|
||||
"Yellow",
|
||||
"Grey",
|
||||
"Dark Grey"
|
||||
]
|
||||
}],
|
||||
},
|
||||
options: {
|
||||
responsive: true
|
||||
}
|
||||
};
|
||||
|
||||
var polarData = [
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color:"#F7464A",
|
||||
highlight: "#FF5A5E",
|
||||
label: "Red"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#46BFBD",
|
||||
highlight: "#5AD3D1",
|
||||
label: "Green"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#FDB45C",
|
||||
highlight: "#FFC870",
|
||||
label: "Yellow"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#949FB1",
|
||||
highlight: "#A8B3C5",
|
||||
label: "Grey"
|
||||
},
|
||||
{
|
||||
value: randomScalingFactor(),
|
||||
color: "#4D5360",
|
||||
highlight: "#616774",
|
||||
label: "Dark Grey"
|
||||
}
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("chart-area").getContext("2d");
|
||||
window.myPolarArea = new Chart(ctx).PolarArea(config);
|
||||
};
|
||||
|
||||
];
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, piece) {
|
||||
$.each(piece.data, function(j, value) {
|
||||
config.data.datasets[i].data[j] = randomScalingFactor();
|
||||
//config.data.datasets.backgroundColor[i] = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
});
|
||||
});
|
||||
window.myPolarArea.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
window.onload = function(){
|
||||
var ctx = document.getElementById("chart-area").getContext("2d");
|
||||
window.myPolarArea = new Chart(ctx).PolarArea(polarData, {
|
||||
responsive:true
|
||||
});
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function(){
|
||||
$.each(polarData, function(i, piece){
|
||||
polarData[i].value = randomScalingFactor();
|
||||
polarData[i].color = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
|
||||
});
|
||||
window.myPolarArea.update();
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+49
-52
@@ -1,64 +1,61 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Radar Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:30%">
|
||||
<canvas id="canvas" height="450" width="450"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
|
||||
<head>
|
||||
<title>Radar Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<script>
|
||||
<body>
|
||||
<div style="width:100%">
|
||||
<canvas id="canvas" height="450" width="450"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
|
||||
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
|
||||
var randomColorFactor = function(){ return Math.round(Math.random()*255)};
|
||||
var config = {
|
||||
data: {
|
||||
labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"],
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
backgroundColor: "rgba(220,220,220,0.2)",
|
||||
pointBackgroundColor: "rgba(220,220,220,1)",
|
||||
data: [null, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
backgroundColor: "rgba(151,187,205,0.2)",
|
||||
pointBackgroundColor: "rgba(151,187,205,1)",
|
||||
hoverPointBackgroundColor: "#fff",
|
||||
pointHighlightStroke: "rgba(151,187,205,1)",
|
||||
data: [null, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true
|
||||
}
|
||||
};
|
||||
|
||||
var radarChartData = {
|
||||
labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"],
|
||||
datasets: [
|
||||
{
|
||||
label: "My First dataset",
|
||||
fillColor: "rgba(220,220,220,0.2)",
|
||||
strokeColor: "rgba(220,220,220,1)",
|
||||
pointColor: "rgba(220,220,220,1)",
|
||||
pointStrokeColor: "#fff",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgba(220,220,220,1)",
|
||||
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
|
||||
},
|
||||
{
|
||||
label: "My Second dataset",
|
||||
fillColor: "rgba(151,187,205,0.2)",
|
||||
strokeColor: "rgba(151,187,205,1)",
|
||||
pointColor: "rgba(151,187,205,1)",
|
||||
pointStrokeColor: "#fff",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgba(151,187,205,1)",
|
||||
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
|
||||
}
|
||||
]
|
||||
};
|
||||
window.onload = function() {
|
||||
window.myRadar = new Chart(document.getElementById("canvas").getContext("2d")).Radar(config);
|
||||
};
|
||||
|
||||
window.onload = function(){
|
||||
window.myRadar = new Chart(document.getElementById("canvas").getContext("2d")).Radar(radarChartData, {
|
||||
responsive: true
|
||||
});
|
||||
}
|
||||
$('#randomizeData').click(function() {
|
||||
config.data.datasets[0].backgroundColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.3)';
|
||||
config.data.datasets[0].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
$('#randomizeData').click(function(){
|
||||
radarChartData.datasets[0].fillColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.3)';
|
||||
radarChartData.datasets[0].data = [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()];
|
||||
config.data.datasets[1].backgroundColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.3)';
|
||||
config.data.datasets[1].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
|
||||
|
||||
radarChartData.datasets[1].fillColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.3)';
|
||||
radarChartData.datasets[1].data = [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()];
|
||||
|
||||
window.myRadar.update();
|
||||
window.myRadar.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Scatter Chart Multi Axis</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%">
|
||||
<div>
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
|
||||
var scatterChartData = {
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
xAxisID: "x-axis-1",
|
||||
yAxisID: "y-axis-1",
|
||||
data: [{
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}]
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
xAxisID: "x-axis-1",
|
||||
yAxisID: "y-axis-2",
|
||||
data: [{
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}]
|
||||
}]
|
||||
};
|
||||
|
||||
$.each(scatterChartData.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.1);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(scatterChartData);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myScatter = new Chart(ctx).Scatter({
|
||||
data: scatterChartData,
|
||||
options: {
|
||||
responsive: true,
|
||||
hoverMode: 'single',
|
||||
scales: {
|
||||
xAxes: [{
|
||||
position: "bottom",
|
||||
gridLines: {
|
||||
zeroLineColor: "rgba(0,0,0,1)"
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
display: true,
|
||||
position: "left",
|
||||
id: "y-axis-1",
|
||||
}, {
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
display: true,
|
||||
position: "right",
|
||||
id: "y-axis-2",
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
drawOnChartArea: false, // only want the grid lines for one axis to show up
|
||||
},
|
||||
}],
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
scatterChartData.datasets[0].data = [{
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}];
|
||||
scatterChartData.datasets[1].data = [{
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}]
|
||||
window.myScatter.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,155 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Scatter Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%">
|
||||
<div>
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random() * 255) + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
|
||||
var scatterChartData = {
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
data: [{
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}]
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
data: [{
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}]
|
||||
}]
|
||||
};
|
||||
|
||||
$.each(scatterChartData.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.1);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(scatterChartData);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myScatter = new Chart(ctx).Scatter({
|
||||
data: scatterChartData,
|
||||
options: {
|
||||
responsive: true,
|
||||
hoverMode: 'single', // should always use single for a scatter chart
|
||||
scales: {
|
||||
xAxes: [{
|
||||
gridLines: {
|
||||
zeroLineColor: "rgba(0,0,0,1)"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
scatterChartData.datasets[0].data = [{
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}];
|
||||
scatterChartData.datasets[1].data = [{
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}]
|
||||
window.myScatter.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,329 +0,0 @@
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
|
||||
var defaultConfig = {
|
||||
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
|
||||
scaleBeginAtZero : true,
|
||||
|
||||
//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 to show horizontal lines (except X axis)
|
||||
scaleShowHorizontalLines: true,
|
||||
|
||||
//Boolean - Whether to show vertical lines (except Y axis)
|
||||
scaleShowVerticalLines: true,
|
||||
|
||||
//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,
|
||||
|
||||
//String - A legend template
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
|
||||
|
||||
};
|
||||
|
||||
|
||||
Chart.Type.extend({
|
||||
name: "Bar",
|
||||
defaults : defaultConfig,
|
||||
initialize: function(data){
|
||||
|
||||
// Save data as a source for updating of values & methods
|
||||
this.data = data;
|
||||
|
||||
//Expose options as a scope variable here so we can access it in the ScaleClass
|
||||
var options = this.options;
|
||||
|
||||
this.ScaleClass = Chart.Scale.extend({
|
||||
offsetGridLines : true,
|
||||
calculateBarX : function(datasetCount, datasetIndex, barIndex){
|
||||
//Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar
|
||||
var xWidth = this.calculateBaseWidth(),
|
||||
xAbsolute = this.calculateX(barIndex) - (xWidth/2),
|
||||
barWidth = this.calculateBarWidth(datasetCount);
|
||||
|
||||
return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2;
|
||||
},
|
||||
calculateBaseWidth : function(){
|
||||
return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing);
|
||||
},
|
||||
calculateBarWidth : function(datasetCount){
|
||||
//The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
|
||||
var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing);
|
||||
|
||||
return (baseWidth / datasetCount);
|
||||
}
|
||||
});
|
||||
|
||||
this.datasets = [];
|
||||
|
||||
//Set up tooltip events on the chart
|
||||
if (this.options.showTooltips){
|
||||
helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
|
||||
var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : [];
|
||||
|
||||
this.eachBars(function(bar){
|
||||
bar.restore(['fillColor', 'strokeColor']);
|
||||
});
|
||||
helpers.each(activeBars, function(activeBar){
|
||||
activeBar.fillColor = activeBar.highlightFill;
|
||||
activeBar.strokeColor = activeBar.highlightStroke;
|
||||
});
|
||||
this.showTooltip(activeBars);
|
||||
});
|
||||
}
|
||||
|
||||
//Declare the extension of the default point, to cater for the options passed in to the constructor
|
||||
this.BarClass = Chart.Rectangle.extend({
|
||||
strokeWidth : this.options.barStrokeWidth,
|
||||
showStroke : this.options.barShowStroke,
|
||||
ctx : this.chart.ctx
|
||||
});
|
||||
|
||||
//Iterate through each of the datasets, and build this into a property of the chart
|
||||
helpers.each(data.datasets,function(dataset,datasetIndex){
|
||||
|
||||
var datasetObject = {
|
||||
label : dataset.label || null,
|
||||
fillColor : dataset.fillColor,
|
||||
strokeColor : dataset.strokeColor,
|
||||
bars : []
|
||||
};
|
||||
|
||||
this.datasets.push(datasetObject);
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
datasetObject.bars.push(new this.BarClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.strokeColor,
|
||||
fillColor : dataset.fillColor,
|
||||
highlightFill : dataset.highlightFill || dataset.fillColor,
|
||||
highlightStroke : dataset.highlightStroke || dataset.strokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
},this);
|
||||
|
||||
this.buildScale(data.labels);
|
||||
|
||||
this.BarClass.prototype.base = this.scale.endPoint;
|
||||
|
||||
this.eachBars(function(bar, index, datasetIndex){
|
||||
helpers.extend(bar, {
|
||||
width : this.scale.calculateBarWidth(this.datasets.length),
|
||||
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
|
||||
y: this.scale.endPoint
|
||||
});
|
||||
bar.save();
|
||||
}, this);
|
||||
|
||||
this.render();
|
||||
},
|
||||
update : function(){
|
||||
//Iterate through each of the datasets, and build this into a property of the chart
|
||||
helpers.each(this.data.datasets,function(dataset,datasetIndex){
|
||||
|
||||
helpers.extend(this.datasets[datasetIndex], {
|
||||
label : dataset.label || null,
|
||||
fillColor : dataset.fillColor,
|
||||
strokeColor : dataset.strokeColor,
|
||||
});
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
helpers.extend(this.datasets[datasetIndex].bars[index], {
|
||||
value : dataPoint,
|
||||
label : this.data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.strokeColor,
|
||||
fillColor : dataset.fillColor,
|
||||
highlightFill : dataset.highlightFill || dataset.fillColor,
|
||||
highlightStroke : dataset.highlightStroke || dataset.strokeColor
|
||||
});
|
||||
},this);
|
||||
|
||||
},this);
|
||||
|
||||
this.scale.update();
|
||||
// Reset any highlight colours before updating.
|
||||
helpers.each(this.activeElements, function(activeElement){
|
||||
activeElement.restore(['fillColor', 'strokeColor']);
|
||||
});
|
||||
|
||||
this.eachBars(function(bar){
|
||||
bar.save();
|
||||
});
|
||||
this.render();
|
||||
},
|
||||
eachBars : function(callback){
|
||||
helpers.each(this.datasets,function(dataset, datasetIndex){
|
||||
helpers.each(dataset.bars, callback, this, datasetIndex);
|
||||
},this);
|
||||
},
|
||||
getBarsAtEvent : function(e){
|
||||
var barsArray = [],
|
||||
eventPosition = helpers.getRelativePosition(e),
|
||||
datasetIterator = function(dataset){
|
||||
barsArray.push(dataset.bars[barIndex]);
|
||||
},
|
||||
barIndex;
|
||||
|
||||
for (var datasetIndex = 0; datasetIndex < this.datasets.length; datasetIndex++) {
|
||||
for (barIndex = 0; barIndex < this.datasets[datasetIndex].bars.length; barIndex++) {
|
||||
if (this.datasets[datasetIndex].bars[barIndex].inRange(eventPosition.x,eventPosition.y)){
|
||||
helpers.each(this.datasets, datasetIterator);
|
||||
return barsArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return barsArray;
|
||||
},
|
||||
buildScale : function(labels){
|
||||
var self = this;
|
||||
|
||||
var dataTotal = function(){
|
||||
var values = [];
|
||||
self.eachBars(function(bar){
|
||||
values.push(bar.value);
|
||||
});
|
||||
return values;
|
||||
};
|
||||
|
||||
var scaleOptions = {
|
||||
templateString : this.options.scaleLabel,
|
||||
height : this.chart.height,
|
||||
width : this.chart.width,
|
||||
ctx : this.chart.ctx,
|
||||
textColor : this.options.scaleFontColor,
|
||||
fontSize : this.options.scaleFontSize,
|
||||
fontStyle : this.options.scaleFontStyle,
|
||||
fontFamily : this.options.scaleFontFamily,
|
||||
valuesCount : labels.length,
|
||||
beginAtZero : this.options.scaleBeginAtZero,
|
||||
integersOnly : this.options.scaleIntegersOnly,
|
||||
calculateYRange: function(currentHeight){
|
||||
var updatedRanges = helpers.calculateScaleRange(
|
||||
dataTotal(),
|
||||
currentHeight,
|
||||
this.fontSize,
|
||||
this.beginAtZero,
|
||||
this.integersOnly
|
||||
);
|
||||
helpers.extend(this, updatedRanges);
|
||||
},
|
||||
xLabels : labels,
|
||||
font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
|
||||
lineWidth : this.options.scaleLineWidth,
|
||||
lineColor : this.options.scaleLineColor,
|
||||
showHorizontalLines : this.options.scaleShowHorizontalLines,
|
||||
showVerticalLines : this.options.scaleShowVerticalLines,
|
||||
gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
|
||||
gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
|
||||
padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0,
|
||||
showLabels : this.options.scaleShowLabels,
|
||||
display : this.options.showScale
|
||||
};
|
||||
|
||||
if (this.options.scaleOverride){
|
||||
helpers.extend(scaleOptions, {
|
||||
calculateYRange: helpers.noop,
|
||||
steps: this.options.scaleSteps,
|
||||
stepValue: this.options.scaleStepWidth,
|
||||
min: this.options.scaleStartValue,
|
||||
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
|
||||
});
|
||||
}
|
||||
|
||||
this.scale = new this.ScaleClass(scaleOptions);
|
||||
},
|
||||
addData : function(valuesArray,label){
|
||||
//Map the values array for each of the datasets
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].bars.push(new this.BarClass({
|
||||
value : value,
|
||||
label : label,
|
||||
datasetLabel: this.datasets[datasetIndex].label,
|
||||
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
width : this.scale.calculateBarWidth(this.datasets.length),
|
||||
base : this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].strokeColor,
|
||||
fillColor : this.datasets[datasetIndex].fillColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.addXLabel(label);
|
||||
//Then re-render the chart.
|
||||
this.update();
|
||||
},
|
||||
removeData : function(){
|
||||
this.scale.removeXLabel();
|
||||
//Then re-render the chart.
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
dataset.bars.shift();
|
||||
},this);
|
||||
this.update();
|
||||
},
|
||||
reflow : function(){
|
||||
helpers.extend(this.BarClass.prototype,{
|
||||
y: this.scale.endPoint,
|
||||
base : this.scale.endPoint
|
||||
});
|
||||
var newScaleProps = helpers.extend({
|
||||
height : this.chart.height,
|
||||
width : this.chart.width
|
||||
});
|
||||
this.scale.update(newScaleProps);
|
||||
},
|
||||
draw : function(ease){
|
||||
var easingDecimal = ease || 1;
|
||||
this.clear();
|
||||
|
||||
var ctx = this.chart.ctx;
|
||||
|
||||
this.scale.draw(easingDecimal);
|
||||
|
||||
//Draw all the bars for each dataset
|
||||
helpers.each(this.datasets,function(dataset,datasetIndex){
|
||||
helpers.each(dataset.bars,function(bar,index){
|
||||
if (bar.hasValue()){
|
||||
bar.base = this.scale.endPoint;
|
||||
//Transition then draw
|
||||
bar.transition({
|
||||
x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
|
||||
y : this.scale.calculateY(bar.value),
|
||||
width : this.scale.calculateBarWidth(this.datasets.length)
|
||||
}, easingDecimal).draw();
|
||||
}
|
||||
},this);
|
||||
|
||||
},this);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}).call(this);
|
||||
-2201
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,212 +0,0 @@
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
//Cache a local reference to Chart.helpers
|
||||
helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
//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,
|
||||
|
||||
//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,
|
||||
|
||||
//String - A legend template
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
|
||||
|
||||
};
|
||||
|
||||
Chart.Type.extend({
|
||||
//Passing in a name registers this chart in the Chart namespace
|
||||
name: "Doughnut",
|
||||
//Providing a defaults will also register the deafults in the chart namespace
|
||||
defaults : defaultConfig,
|
||||
//Initialize is fired when the chart is initialized - Data is passed in as a parameter
|
||||
//Config is automatically merged by the core of Chart.js, and is available at this.options
|
||||
initialize: function(data){
|
||||
|
||||
// Save data as a source for updating of values & methods
|
||||
this.data = data;
|
||||
|
||||
//Declare segments as a static property to prevent inheriting across the Chart type prototype
|
||||
this.segments = [];
|
||||
this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2;
|
||||
|
||||
this.SegmentArc = Chart.Arc.extend({
|
||||
ctx : this.chart.ctx,
|
||||
x : this.chart.width/2,
|
||||
y : this.chart.height/2
|
||||
});
|
||||
|
||||
//Set up tooltip events on the chart
|
||||
if (this.options.showTooltips){
|
||||
helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
|
||||
var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
|
||||
|
||||
helpers.each(this.segments,function(segment){
|
||||
segment.restore(["fillColor"]);
|
||||
});
|
||||
helpers.each(activeSegments,function(activeSegment){
|
||||
activeSegment.fillColor = activeSegment.highlightColor;
|
||||
});
|
||||
this.showTooltip(activeSegments);
|
||||
});
|
||||
}
|
||||
this.calculateTotal(data);
|
||||
|
||||
helpers.each(data,function(datapoint, index){
|
||||
if (!datapoint.color) {
|
||||
datapoint.color = 'hsl(' + (360 * index / data.length) + ', 100%, 50%)';
|
||||
}
|
||||
this.addData(datapoint, index, true);
|
||||
},this);
|
||||
|
||||
this.render();
|
||||
},
|
||||
getSegmentsAtEvent : function(e){
|
||||
var segmentsArray = [];
|
||||
|
||||
var location = helpers.getRelativePosition(e);
|
||||
|
||||
helpers.each(this.segments,function(segment){
|
||||
if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
|
||||
},this);
|
||||
return segmentsArray;
|
||||
},
|
||||
addData : function(segment, atIndex, silent){
|
||||
var index = atIndex || this.segments.length;
|
||||
this.segments.splice(index, 0, new this.SegmentArc({
|
||||
value : segment.value,
|
||||
outerRadius : (this.options.animateScale) ? 0 : this.outerRadius,
|
||||
innerRadius : (this.options.animateScale) ? 0 : (this.outerRadius/100) * this.options.percentageInnerCutout,
|
||||
fillColor : segment.color,
|
||||
highlightColor : segment.highlight || segment.color,
|
||||
showStroke : this.options.segmentShowStroke,
|
||||
strokeWidth : this.options.segmentStrokeWidth,
|
||||
strokeColor : this.options.segmentStrokeColor,
|
||||
startAngle : Math.PI * 1.5,
|
||||
circumference : (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value),
|
||||
label : segment.label
|
||||
}));
|
||||
if (!silent){
|
||||
this.reflow();
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
calculateCircumference : function(value) {
|
||||
if ( this.total > 0 ) {
|
||||
return (Math.PI*2)*(value / this.total);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
calculateTotal : function(data){
|
||||
this.total = 0;
|
||||
helpers.each(data,function(segment){
|
||||
this.total += Math.abs(segment.value);
|
||||
},this);
|
||||
},
|
||||
update : function(){
|
||||
|
||||
// Map new data to data points
|
||||
if(this.data.length == this.segments.length){
|
||||
helpers.each(this.data, function(segment, i){
|
||||
helpers.extend(this.segments[i], {
|
||||
value : segment.value,
|
||||
fillColor : segment.color,
|
||||
highlightColor : segment.highlight || segment.color,
|
||||
showStroke : this.options.segmentShowStroke,
|
||||
strokeWidth : this.options.segmentStrokeWidth,
|
||||
strokeColor : this.options.segmentStrokeColor,
|
||||
label : segment.label
|
||||
});
|
||||
}, this);
|
||||
} else{
|
||||
// Data size changed without properly inserting, just redraw the chart
|
||||
this.initialize(this.data);
|
||||
}
|
||||
|
||||
this.calculateTotal(this.segments);
|
||||
|
||||
// Reset any highlight colours before updating.
|
||||
helpers.each(this.activeElements, function(activeElement){
|
||||
activeElement.restore(['fillColor']);
|
||||
});
|
||||
|
||||
helpers.each(this.segments,function(segment){
|
||||
segment.save();
|
||||
});
|
||||
this.render();
|
||||
},
|
||||
|
||||
removeData: function(atIndex){
|
||||
var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
|
||||
this.segments.splice(indexToDelete, 1);
|
||||
this.reflow();
|
||||
this.update();
|
||||
},
|
||||
|
||||
reflow : function(){
|
||||
helpers.extend(this.SegmentArc.prototype,{
|
||||
x : this.chart.width/2,
|
||||
y : this.chart.height/2
|
||||
});
|
||||
this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2;
|
||||
helpers.each(this.segments, function(segment){
|
||||
segment.update({
|
||||
outerRadius : this.outerRadius,
|
||||
innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
draw : function(easeDecimal){
|
||||
var animDecimal = (easeDecimal) ? easeDecimal : 1;
|
||||
this.clear();
|
||||
helpers.each(this.segments,function(segment,index){
|
||||
segment.transition({
|
||||
circumference : this.calculateCircumference(segment.value),
|
||||
outerRadius : this.outerRadius,
|
||||
innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
|
||||
},animDecimal);
|
||||
|
||||
segment.endAngle = segment.startAngle + segment.circumference;
|
||||
|
||||
segment.draw();
|
||||
if (index === 0){
|
||||
segment.startAngle = Math.PI * 1.5;
|
||||
}
|
||||
//Check to see if it's the last segment, if not get the next and update the start angle
|
||||
if (index < this.segments.length-1){
|
||||
this.segments[index+1].startAngle = segment.endAngle;
|
||||
}
|
||||
},this);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Chart.types.Doughnut.extend({
|
||||
name : "Pie",
|
||||
defaults : helpers.merge(defaultConfig,{percentageInnerCutout : 0})
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -1,408 +0,0 @@
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
|
||||
///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 to show horizontal lines (except X axis)
|
||||
scaleShowHorizontalLines: true,
|
||||
|
||||
//Boolean - Whether to show vertical lines (except Y axis)
|
||||
scaleShowVerticalLines: true,
|
||||
|
||||
//Boolean - Whether the line is curved between points
|
||||
bezierCurve : true,
|
||||
|
||||
//Number - Tension of the bezier curve between points
|
||||
bezierCurveTension : 0.4,
|
||||
|
||||
//Boolean - Whether to show a dot for each point
|
||||
pointDot : true,
|
||||
|
||||
//Number - Radius of each point dot in pixels
|
||||
pointDotRadius : 4,
|
||||
|
||||
//Number - Pixel width of point dot stroke
|
||||
pointDotStrokeWidth : 1,
|
||||
|
||||
//Number - amount extra to add to the radius to cater for hit detection outside the drawn point
|
||||
pointHitDetectionRadius : 20,
|
||||
|
||||
//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,
|
||||
|
||||
//String - A legend template
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>",
|
||||
|
||||
//Boolean - Whether to horizontally center the label and point dot inside the grid
|
||||
offsetGridLines : false
|
||||
|
||||
};
|
||||
|
||||
|
||||
Chart.Type.extend({
|
||||
name: "Line",
|
||||
defaults : defaultConfig,
|
||||
initialize: function(data){
|
||||
// Save data as a source for updating of values & methods
|
||||
this.data = data;
|
||||
|
||||
//Declare the extension of the default point, to cater for the options passed in to the constructor
|
||||
this.PointClass = Chart.Point.extend({
|
||||
offsetGridLines : this.options.offsetGridLines,
|
||||
strokeWidth : this.options.pointDotStrokeWidth,
|
||||
radius : this.options.pointDotRadius,
|
||||
display: this.options.pointDot,
|
||||
hitDetectionRadius : this.options.pointHitDetectionRadius,
|
||||
ctx : this.chart.ctx,
|
||||
inRange : function(mouseX){
|
||||
return (Math.pow(mouseX-this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius,2));
|
||||
}
|
||||
});
|
||||
|
||||
this.datasets = [];
|
||||
|
||||
//Set up tooltip events on the chart
|
||||
if (this.options.showTooltips){
|
||||
helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
|
||||
var activePoints = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : [];
|
||||
this.eachPoints(function(point){
|
||||
point.restore(['fillColor', 'strokeColor']);
|
||||
});
|
||||
helpers.each(activePoints, function(activePoint){
|
||||
activePoint.fillColor = activePoint.highlightFill;
|
||||
activePoint.strokeColor = activePoint.highlightStroke;
|
||||
});
|
||||
this.showTooltip(activePoints);
|
||||
});
|
||||
}
|
||||
|
||||
//Iterate through each of the datasets, and build this into a property of the chart
|
||||
helpers.each(data.datasets,function(dataset){
|
||||
|
||||
var datasetObject = {
|
||||
label : dataset.label || null,
|
||||
fillColor : dataset.fillColor,
|
||||
strokeColor : dataset.strokeColor,
|
||||
pointColor : dataset.pointColor,
|
||||
pointStrokeColor : dataset.pointStrokeColor,
|
||||
points : []
|
||||
};
|
||||
|
||||
this.datasets.push(datasetObject);
|
||||
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.buildScale(data.labels);
|
||||
|
||||
|
||||
this.eachPoints(function(point, index){
|
||||
helpers.extend(point, {
|
||||
x: this.scale.calculateX(index),
|
||||
y: this.scale.endPoint
|
||||
});
|
||||
point.save();
|
||||
}, this);
|
||||
|
||||
},this);
|
||||
|
||||
|
||||
this.render();
|
||||
},
|
||||
update : function(){
|
||||
//Iterate through each of the datasets, and build this into a property of the chart
|
||||
helpers.each(this.data.datasets,function(dataset,datasetIndex){
|
||||
|
||||
helpers.extend(this.datasets[datasetIndex], {
|
||||
label : dataset.label || null,
|
||||
fillColor : dataset.fillColor,
|
||||
strokeColor : dataset.strokeColor,
|
||||
pointColor : dataset.pointColor,
|
||||
pointStrokeColor : dataset.pointStrokeColor,
|
||||
});
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
helpers.extend(this.datasets[datasetIndex].points[index], {
|
||||
value : dataPoint,
|
||||
label : this.data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
});
|
||||
},this);
|
||||
|
||||
},this);
|
||||
|
||||
this.scale.update();
|
||||
// Reset any highlight colours before updating.
|
||||
helpers.each(this.activeElements, function(activeElement){
|
||||
activeElement.restore(['fillColor', 'strokeColor']);
|
||||
});
|
||||
this.eachPoints(function(point){
|
||||
point.save();
|
||||
});
|
||||
this.render();
|
||||
},
|
||||
eachPoints : function(callback){
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
helpers.each(dataset.points,callback,this);
|
||||
},this);
|
||||
},
|
||||
getPointsAtEvent : function(e){
|
||||
var pointsArray = [],
|
||||
eventPosition = helpers.getRelativePosition(e);
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
helpers.each(dataset.points,function(point){
|
||||
if (point.inRange(eventPosition.x,eventPosition.y)) pointsArray.push(point);
|
||||
});
|
||||
},this);
|
||||
return pointsArray;
|
||||
},
|
||||
buildScale : function(labels){
|
||||
var self = this;
|
||||
|
||||
var dataTotal = function(){
|
||||
var values = [];
|
||||
self.eachPoints(function(point){
|
||||
values.push(point.value);
|
||||
});
|
||||
|
||||
return values;
|
||||
};
|
||||
|
||||
var scaleOptions = {
|
||||
templateString : this.options.scaleLabel,
|
||||
height : this.chart.height,
|
||||
width : this.chart.width,
|
||||
ctx : this.chart.ctx,
|
||||
textColor : this.options.scaleFontColor,
|
||||
offsetGridLines : this.options.offsetGridLines,
|
||||
fontSize : this.options.scaleFontSize,
|
||||
fontStyle : this.options.scaleFontStyle,
|
||||
fontFamily : this.options.scaleFontFamily,
|
||||
valuesCount : labels.length,
|
||||
beginAtZero : this.options.scaleBeginAtZero,
|
||||
integersOnly : this.options.scaleIntegersOnly,
|
||||
calculateYRange : function(currentHeight){
|
||||
var updatedRanges = helpers.calculateScaleRange(
|
||||
dataTotal(),
|
||||
currentHeight,
|
||||
this.fontSize,
|
||||
this.beginAtZero,
|
||||
this.integersOnly
|
||||
);
|
||||
helpers.extend(this, updatedRanges);
|
||||
},
|
||||
xLabels : labels,
|
||||
font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
|
||||
lineWidth : this.options.scaleLineWidth,
|
||||
lineColor : this.options.scaleLineColor,
|
||||
showHorizontalLines : this.options.scaleShowHorizontalLines,
|
||||
showVerticalLines : this.options.scaleShowVerticalLines,
|
||||
gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
|
||||
gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
|
||||
padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
|
||||
showLabels : this.options.scaleShowLabels,
|
||||
display : this.options.showScale
|
||||
};
|
||||
|
||||
if (this.options.scaleOverride){
|
||||
helpers.extend(scaleOptions, {
|
||||
calculateYRange: helpers.noop,
|
||||
steps: this.options.scaleSteps,
|
||||
stepValue: this.options.scaleStepWidth,
|
||||
min: this.options.scaleStartValue,
|
||||
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.scale = new Chart.Scale(scaleOptions);
|
||||
},
|
||||
addData : function(valuesArray,label){
|
||||
//Map the values array for each of the datasets
|
||||
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
datasetLabel: this.datasets[datasetIndex].label,
|
||||
x: this.scale.calculateX(this.scale.valuesCount+1),
|
||||
y: this.scale.endPoint,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.addXLabel(label);
|
||||
//Then re-render the chart.
|
||||
this.update();
|
||||
},
|
||||
removeData : function(){
|
||||
this.scale.removeXLabel();
|
||||
//Then re-render the chart.
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
dataset.points.shift();
|
||||
},this);
|
||||
this.update();
|
||||
},
|
||||
reflow : function(){
|
||||
var newScaleProps = helpers.extend({
|
||||
height : this.chart.height,
|
||||
width : this.chart.width
|
||||
});
|
||||
this.scale.update(newScaleProps);
|
||||
},
|
||||
draw : function(ease){
|
||||
var easingDecimal = ease || 1;
|
||||
this.clear();
|
||||
|
||||
var ctx = this.chart.ctx;
|
||||
|
||||
// Some helper methods for getting the next/prev points
|
||||
var hasValue = function(item){
|
||||
return item.value !== null;
|
||||
},
|
||||
nextPoint = function(point, collection, index){
|
||||
return helpers.findNextWhere(collection, hasValue, index) || point;
|
||||
},
|
||||
previousPoint = function(point, collection, index){
|
||||
return helpers.findPreviousWhere(collection, hasValue, index) || point;
|
||||
};
|
||||
|
||||
this.scale.draw(easingDecimal);
|
||||
|
||||
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
var pointsWithValues = helpers.where(dataset.points, hasValue);
|
||||
|
||||
//Transition each point first so that the line and point drawing isn't out of sync
|
||||
//We can use this extra loop to calculate the control points of this dataset also in this loop
|
||||
|
||||
helpers.each(dataset.points, function(point, index){
|
||||
if (point.hasValue()){
|
||||
point.transition({
|
||||
y : this.scale.calculateY(point.value),
|
||||
x : this.scale.calculateX(index)
|
||||
}, easingDecimal);
|
||||
}
|
||||
},this);
|
||||
|
||||
|
||||
// Control points need to be calculated in a seperate loop, because we need to know the current x/y of the point
|
||||
// This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed
|
||||
if (this.options.bezierCurve){
|
||||
helpers.each(pointsWithValues, function(point, index){
|
||||
var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0;
|
||||
point.controlPoints = helpers.splineCurve(
|
||||
previousPoint(point, pointsWithValues, index),
|
||||
point,
|
||||
nextPoint(point, pointsWithValues, index),
|
||||
tension
|
||||
);
|
||||
|
||||
// Prevent the bezier going outside of the bounds of the graph
|
||||
|
||||
// Cap puter bezier handles to the upper/lower scale bounds
|
||||
if (point.controlPoints.outer.y > this.scale.endPoint){
|
||||
point.controlPoints.outer.y = this.scale.endPoint;
|
||||
}
|
||||
else if (point.controlPoints.outer.y < this.scale.startPoint){
|
||||
point.controlPoints.outer.y = this.scale.startPoint;
|
||||
}
|
||||
|
||||
// Cap inner bezier handles to the upper/lower scale bounds
|
||||
if (point.controlPoints.inner.y > this.scale.endPoint){
|
||||
point.controlPoints.inner.y = this.scale.endPoint;
|
||||
}
|
||||
else if (point.controlPoints.inner.y < this.scale.startPoint){
|
||||
point.controlPoints.inner.y = this.scale.startPoint;
|
||||
}
|
||||
},this);
|
||||
}
|
||||
|
||||
|
||||
//Draw the line between all the points
|
||||
ctx.lineWidth = this.options.datasetStrokeWidth;
|
||||
ctx.strokeStyle = dataset.strokeColor;
|
||||
ctx.beginPath();
|
||||
|
||||
helpers.each(pointsWithValues, function(point, index){
|
||||
if (index === 0){
|
||||
ctx.moveTo(point.x, point.y);
|
||||
}
|
||||
else{
|
||||
if(this.options.bezierCurve){
|
||||
var previous = previousPoint(point, pointsWithValues, index);
|
||||
|
||||
ctx.bezierCurveTo(
|
||||
previous.controlPoints.outer.x,
|
||||
previous.controlPoints.outer.y,
|
||||
point.controlPoints.inner.x,
|
||||
point.controlPoints.inner.y,
|
||||
point.x,
|
||||
point.y
|
||||
);
|
||||
}
|
||||
else{
|
||||
ctx.lineTo(point.x,point.y);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
if (this.options.datasetFill && pointsWithValues.length > 0){
|
||||
//Round off the line by going to the base of the chart, back to the start, then fill.
|
||||
ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint);
|
||||
ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint);
|
||||
ctx.fillStyle = dataset.fillColor;
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
//Now draw the points over the line
|
||||
//A little inefficient double looping, but better than the line
|
||||
//lagging behind the point positions
|
||||
helpers.each(pointsWithValues,function(point){
|
||||
point.draw();
|
||||
});
|
||||
},this);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}).call(this);
|
||||
@@ -1,269 +0,0 @@
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
//Cache a local reference to Chart.helpers
|
||||
helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
//Boolean - Show a backdrop to the scale label
|
||||
scaleShowLabelBackdrop : true,
|
||||
|
||||
//String - The colour of the label backdrop
|
||||
scaleBackdropColor : "rgba(255,255,255,0.75)",
|
||||
|
||||
// Boolean - Whether the scale should begin at zero
|
||||
scaleBeginAtZero : true,
|
||||
|
||||
//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 - Show line for each value in the scale
|
||||
scaleShowLine : true,
|
||||
|
||||
//Boolean - Stroke a line around each segment in the chart
|
||||
segmentShowStroke : true,
|
||||
|
||||
//String - The colour of the stroke on each segment.
|
||||
segmentStrokeColor : "#fff",
|
||||
|
||||
//Number - The width of the stroke value in pixels
|
||||
segmentStrokeWidth : 2,
|
||||
|
||||
//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,
|
||||
|
||||
//String - A legend template
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
|
||||
};
|
||||
|
||||
|
||||
Chart.Type.extend({
|
||||
//Passing in a name registers this chart in the Chart namespace
|
||||
name: "PolarArea",
|
||||
//Providing a defaults will also register the deafults in the chart namespace
|
||||
defaults : defaultConfig,
|
||||
//Initialize is fired when the chart is initialized - Data is passed in as a parameter
|
||||
//Config is automatically merged by the core of Chart.js, and is available at this.options
|
||||
initialize: function(data){
|
||||
// Save data as a source for updating of values & methods
|
||||
this.data = data;
|
||||
|
||||
this.segments = [];
|
||||
//Declare segment class as a chart instance specific class, so it can share props for this instance
|
||||
this.SegmentArc = Chart.Arc.extend({
|
||||
showStroke : this.options.segmentShowStroke,
|
||||
strokeWidth : this.options.segmentStrokeWidth,
|
||||
strokeColor : this.options.segmentStrokeColor,
|
||||
ctx : this.chart.ctx,
|
||||
innerRadius : 0,
|
||||
x : this.chart.width/2,
|
||||
y : this.chart.height/2
|
||||
});
|
||||
this.scale = new Chart.RadialScale({
|
||||
display: this.options.showScale,
|
||||
fontStyle: this.options.scaleFontStyle,
|
||||
fontSize: this.options.scaleFontSize,
|
||||
fontFamily: this.options.scaleFontFamily,
|
||||
fontColor: this.options.scaleFontColor,
|
||||
showLabels: this.options.scaleShowLabels,
|
||||
showLabelBackdrop: this.options.scaleShowLabelBackdrop,
|
||||
backdropColor: this.options.scaleBackdropColor,
|
||||
backdropPaddingY : this.options.scaleBackdropPaddingY,
|
||||
backdropPaddingX: this.options.scaleBackdropPaddingX,
|
||||
lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0,
|
||||
lineColor: this.options.scaleLineColor,
|
||||
lineArc: true,
|
||||
width: this.chart.width,
|
||||
height: this.chart.height,
|
||||
xCenter: this.chart.width/2,
|
||||
yCenter: this.chart.height/2,
|
||||
ctx : this.chart.ctx,
|
||||
templateString: this.options.scaleLabel,
|
||||
valuesCount: data.length
|
||||
});
|
||||
|
||||
this.updateScaleRange(data);
|
||||
|
||||
this.scale.update();
|
||||
|
||||
helpers.each(data,function(segment,index){
|
||||
this.addData(segment,index,true);
|
||||
},this);
|
||||
|
||||
//Set up tooltip events on the chart
|
||||
if (this.options.showTooltips){
|
||||
helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
|
||||
var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
|
||||
helpers.each(this.segments,function(segment){
|
||||
segment.restore(["fillColor"]);
|
||||
});
|
||||
helpers.each(activeSegments,function(activeSegment){
|
||||
activeSegment.fillColor = activeSegment.highlightColor;
|
||||
});
|
||||
this.showTooltip(activeSegments);
|
||||
});
|
||||
}
|
||||
|
||||
this.render();
|
||||
},
|
||||
getSegmentsAtEvent : function(e){
|
||||
var segmentsArray = [];
|
||||
|
||||
var location = helpers.getRelativePosition(e);
|
||||
|
||||
helpers.each(this.segments,function(segment){
|
||||
if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
|
||||
},this);
|
||||
return segmentsArray;
|
||||
},
|
||||
addData : function(segment, atIndex, silent){
|
||||
var index = atIndex || this.segments.length;
|
||||
|
||||
this.segments.splice(index, 0, new this.SegmentArc({
|
||||
fillColor: segment.color,
|
||||
highlightColor: segment.highlight || segment.color,
|
||||
label: segment.label,
|
||||
value: segment.value,
|
||||
outerRadius: (this.options.animateScale) ? 0 : this.scale.calculateCenterOffset(segment.value),
|
||||
circumference: (this.options.animateRotate) ? 0 : this.scale.getCircumference(),
|
||||
startAngle: Math.PI * 1.5
|
||||
}));
|
||||
if (!silent){
|
||||
this.reflow();
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
removeData: function(atIndex){
|
||||
var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
|
||||
this.segments.splice(indexToDelete, 1);
|
||||
this.reflow();
|
||||
this.update();
|
||||
},
|
||||
calculateTotal: function(data){
|
||||
this.total = 0;
|
||||
helpers.each(data,function(segment){
|
||||
this.total += segment.value;
|
||||
},this);
|
||||
this.scale.valuesCount = this.segments.length;
|
||||
},
|
||||
updateScaleRange: function(datapoints){
|
||||
var valuesArray = [];
|
||||
helpers.each(datapoints,function(segment){
|
||||
valuesArray.push(segment.value);
|
||||
});
|
||||
|
||||
var scaleSizes = (this.options.scaleOverride) ?
|
||||
{
|
||||
steps: this.options.scaleSteps,
|
||||
stepValue: this.options.scaleStepWidth,
|
||||
min: this.options.scaleStartValue,
|
||||
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
|
||||
} :
|
||||
helpers.calculateScaleRange(
|
||||
valuesArray,
|
||||
helpers.min([this.chart.width, this.chart.height])/2,
|
||||
this.options.scaleFontSize,
|
||||
this.options.scaleBeginAtZero,
|
||||
this.options.scaleIntegersOnly
|
||||
);
|
||||
|
||||
helpers.extend(
|
||||
this.scale,
|
||||
scaleSizes,
|
||||
{
|
||||
size: helpers.min([this.chart.width, this.chart.height]),
|
||||
xCenter: this.chart.width/2,
|
||||
yCenter: this.chart.height/2
|
||||
}
|
||||
);
|
||||
|
||||
},
|
||||
update : function(){
|
||||
|
||||
// Map new data to data points
|
||||
if(this.data.length == this.segments.length){
|
||||
helpers.each(this.data, function(segment, i){
|
||||
helpers.extend(this.segments[i], {
|
||||
fillColor: segment.color,
|
||||
highlightColor: segment.highlight || segment.color,
|
||||
label: segment.label,
|
||||
value: segment.value,
|
||||
});
|
||||
},this);
|
||||
} else{
|
||||
// Data size changed without properly inserting, just redraw the chart
|
||||
this.initialize(this.data);
|
||||
}
|
||||
|
||||
this.calculateTotal(this.segments);
|
||||
|
||||
helpers.each(this.segments,function(segment){
|
||||
segment.save();
|
||||
});
|
||||
|
||||
this.reflow();
|
||||
this.render();
|
||||
},
|
||||
reflow : function(){
|
||||
helpers.extend(this.SegmentArc.prototype,{
|
||||
x : this.chart.width/2,
|
||||
y : this.chart.height/2
|
||||
});
|
||||
this.updateScaleRange(this.segments);
|
||||
this.scale.update();
|
||||
|
||||
helpers.extend(this.scale,{
|
||||
xCenter: this.chart.width/2,
|
||||
yCenter: this.chart.height/2
|
||||
});
|
||||
|
||||
helpers.each(this.segments, function(segment){
|
||||
segment.update({
|
||||
outerRadius : this.scale.calculateCenterOffset(segment.value)
|
||||
});
|
||||
}, this);
|
||||
|
||||
},
|
||||
draw : function(ease){
|
||||
var easingDecimal = ease || 1;
|
||||
//Clear & draw the canvas
|
||||
this.clear();
|
||||
helpers.each(this.segments,function(segment, index){
|
||||
segment.transition({
|
||||
circumference : this.scale.getCircumference(),
|
||||
outerRadius : this.scale.calculateCenterOffset(segment.value)
|
||||
},easingDecimal);
|
||||
|
||||
segment.endAngle = segment.startAngle + segment.circumference;
|
||||
|
||||
// If we've removed the first segment we need to set the first one to
|
||||
// start at the top.
|
||||
if (index === 0){
|
||||
segment.startAngle = Math.PI * 1.5;
|
||||
}
|
||||
|
||||
//Check to see if it's the last segment, if not get the next and update the start angle
|
||||
if (index < this.segments.length - 1){
|
||||
this.segments[index+1].startAngle = segment.endAngle;
|
||||
}
|
||||
segment.draw();
|
||||
}, this);
|
||||
this.scale.draw();
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -1,372 +0,0 @@
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
|
||||
|
||||
Chart.Type.extend({
|
||||
name: "Radar",
|
||||
defaults:{
|
||||
//Boolean - Whether to show lines for each scale point
|
||||
scaleShowLine : true,
|
||||
|
||||
//Boolean - Whether we show the angle lines out of the radar
|
||||
angleShowLineOut : true,
|
||||
|
||||
//Boolean - Whether to show labels on the scale
|
||||
scaleShowLabels : false,
|
||||
|
||||
// Boolean - Whether the scale should begin at zero
|
||||
scaleBeginAtZero : 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 : 10,
|
||||
|
||||
//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,
|
||||
|
||||
//Number - amount extra to add to the radius to cater for hit detection outside the drawn point
|
||||
pointHitDetectionRadius : 20,
|
||||
|
||||
//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,
|
||||
|
||||
//String - A legend template
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
|
||||
|
||||
},
|
||||
|
||||
initialize: function(data){
|
||||
// Save data as a source for updating of values & methods
|
||||
this.data = data;
|
||||
|
||||
this.PointClass = Chart.Point.extend({
|
||||
strokeWidth : this.options.pointDotStrokeWidth,
|
||||
radius : this.options.pointDotRadius,
|
||||
display: this.options.pointDot,
|
||||
hitDetectionRadius : this.options.pointHitDetectionRadius,
|
||||
ctx : this.chart.ctx
|
||||
});
|
||||
|
||||
this.datasets = [];
|
||||
|
||||
this.buildScale(data);
|
||||
|
||||
//Set up tooltip events on the chart
|
||||
if (this.options.showTooltips){
|
||||
helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
|
||||
var activePointsCollection = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : [];
|
||||
|
||||
this.eachPoints(function(point){
|
||||
point.restore(['fillColor', 'strokeColor']);
|
||||
});
|
||||
helpers.each(activePointsCollection, function(activePoint){
|
||||
activePoint.fillColor = activePoint.highlightFill;
|
||||
activePoint.strokeColor = activePoint.highlightStroke;
|
||||
});
|
||||
|
||||
this.showTooltip(activePointsCollection);
|
||||
});
|
||||
}
|
||||
|
||||
//Iterate through each of the datasets, and build this into a property of the chart
|
||||
helpers.each(data.datasets,function(dataset){
|
||||
|
||||
var datasetObject = {
|
||||
label: dataset.label || null,
|
||||
fillColor : dataset.fillColor,
|
||||
strokeColor : dataset.strokeColor,
|
||||
pointColor : dataset.pointColor,
|
||||
pointStrokeColor : dataset.pointStrokeColor,
|
||||
points : []
|
||||
};
|
||||
|
||||
this.datasets.push(datasetObject);
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
//Add a new point for each piece of data, passing any required data to draw.
|
||||
var pointPosition;
|
||||
if (!this.scale.animation){
|
||||
pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
|
||||
}
|
||||
datasetObject.points.push(new this.PointClass({
|
||||
value : dataPoint,
|
||||
label : data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
|
||||
y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
},this);
|
||||
|
||||
this.render();
|
||||
},
|
||||
eachPoints : function(callback){
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
helpers.each(dataset.points,callback,this);
|
||||
},this);
|
||||
},
|
||||
|
||||
getPointsAtEvent : function(evt){
|
||||
var mousePosition = helpers.getRelativePosition(evt),
|
||||
fromCenter = helpers.getAngleFromPoint({
|
||||
x: this.scale.xCenter,
|
||||
y: this.scale.yCenter
|
||||
}, mousePosition);
|
||||
|
||||
var anglePerIndex = (Math.PI * 2) /this.scale.valuesCount,
|
||||
pointIndex = Math.round((fromCenter.angle - Math.PI * 1.5) / anglePerIndex),
|
||||
activePointsCollection = [];
|
||||
|
||||
// If we're at the top, make the pointIndex 0 to get the first of the array.
|
||||
if (pointIndex >= this.scale.valuesCount || pointIndex < 0){
|
||||
pointIndex = 0;
|
||||
}
|
||||
|
||||
if (fromCenter.distance <= this.scale.drawingArea){
|
||||
helpers.each(this.datasets, function(dataset){
|
||||
activePointsCollection.push(dataset.points[pointIndex]);
|
||||
});
|
||||
}
|
||||
|
||||
return activePointsCollection;
|
||||
},
|
||||
|
||||
buildScale : function(data){
|
||||
this.scale = new Chart.RadialScale({
|
||||
display: this.options.showScale,
|
||||
fontStyle: this.options.scaleFontStyle,
|
||||
fontSize: this.options.scaleFontSize,
|
||||
fontFamily: this.options.scaleFontFamily,
|
||||
fontColor: this.options.scaleFontColor,
|
||||
showLabels: this.options.scaleShowLabels,
|
||||
showLabelBackdrop: this.options.scaleShowLabelBackdrop,
|
||||
backdropColor: this.options.scaleBackdropColor,
|
||||
backdropPaddingY : this.options.scaleBackdropPaddingY,
|
||||
backdropPaddingX: this.options.scaleBackdropPaddingX,
|
||||
lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0,
|
||||
lineColor: this.options.scaleLineColor,
|
||||
angleLineColor : this.options.angleLineColor,
|
||||
angleLineWidth : (this.options.angleShowLineOut) ? this.options.angleLineWidth : 0,
|
||||
// Point labels at the edge of each line
|
||||
pointLabelFontColor : this.options.pointLabelFontColor,
|
||||
pointLabelFontSize : this.options.pointLabelFontSize,
|
||||
pointLabelFontFamily : this.options.pointLabelFontFamily,
|
||||
pointLabelFontStyle : this.options.pointLabelFontStyle,
|
||||
height : this.chart.height,
|
||||
width: this.chart.width,
|
||||
xCenter: this.chart.width/2,
|
||||
yCenter: this.chart.height/2,
|
||||
ctx : this.chart.ctx,
|
||||
templateString: this.options.scaleLabel,
|
||||
labels: data.labels,
|
||||
valuesCount: data.datasets[0].data.length
|
||||
});
|
||||
|
||||
this.scale.setScaleSize();
|
||||
this.updateScaleRange(data.datasets);
|
||||
this.scale.buildYLabels();
|
||||
},
|
||||
updateScaleRange: function(datasets){
|
||||
var valuesArray = (function(){
|
||||
var totalDataArray = [];
|
||||
helpers.each(datasets,function(dataset){
|
||||
if (dataset.data){
|
||||
totalDataArray = totalDataArray.concat(dataset.data);
|
||||
}
|
||||
else {
|
||||
helpers.each(dataset.points, function(point){
|
||||
totalDataArray.push(point.value);
|
||||
});
|
||||
}
|
||||
});
|
||||
return totalDataArray;
|
||||
})();
|
||||
|
||||
|
||||
var scaleSizes = (this.options.scaleOverride) ?
|
||||
{
|
||||
steps: this.options.scaleSteps,
|
||||
stepValue: this.options.scaleStepWidth,
|
||||
min: this.options.scaleStartValue,
|
||||
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
|
||||
} :
|
||||
helpers.calculateScaleRange(
|
||||
valuesArray,
|
||||
helpers.min([this.chart.width, this.chart.height])/2,
|
||||
this.options.scaleFontSize,
|
||||
this.options.scaleBeginAtZero,
|
||||
this.options.scaleIntegersOnly
|
||||
);
|
||||
|
||||
helpers.extend(
|
||||
this.scale,
|
||||
scaleSizes
|
||||
);
|
||||
|
||||
},
|
||||
addData : function(valuesArray,label){
|
||||
//Map the values array for each of the datasets
|
||||
this.scale.valuesCount++;
|
||||
helpers.each(valuesArray,function(value,datasetIndex){
|
||||
var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
|
||||
this.datasets[datasetIndex].points.push(new this.PointClass({
|
||||
value : value,
|
||||
label : label,
|
||||
datasetLabel: this.datasets[datasetIndex].label,
|
||||
x: pointPosition.x,
|
||||
y: pointPosition.y,
|
||||
strokeColor : this.datasets[datasetIndex].pointStrokeColor,
|
||||
fillColor : this.datasets[datasetIndex].pointColor
|
||||
}));
|
||||
},this);
|
||||
|
||||
this.scale.labels.push(label);
|
||||
|
||||
this.reflow();
|
||||
|
||||
this.update();
|
||||
},
|
||||
removeData : function(){
|
||||
this.scale.valuesCount--;
|
||||
this.scale.labels.shift();
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
dataset.points.shift();
|
||||
},this);
|
||||
this.reflow();
|
||||
this.update();
|
||||
},
|
||||
update : function(){
|
||||
//Iterate through each of the datasets, and build this into a property of the chart
|
||||
helpers.each(this.data.datasets,function(dataset,datasetIndex){
|
||||
|
||||
helpers.extend(this.datasets[datasetIndex], {
|
||||
label : dataset.label || null,
|
||||
fillColor : dataset.fillColor,
|
||||
strokeColor : dataset.strokeColor,
|
||||
pointColor : dataset.pointColor,
|
||||
pointStrokeColor : dataset.pointStrokeColor,
|
||||
});
|
||||
|
||||
helpers.each(dataset.data,function(dataPoint,index){
|
||||
helpers.extend(this.datasets[datasetIndex].points[index], {
|
||||
value : dataPoint,
|
||||
label : this.data.labels[index],
|
||||
datasetLabel: dataset.label,
|
||||
strokeColor : dataset.pointStrokeColor,
|
||||
fillColor : dataset.pointColor,
|
||||
highlightFill : dataset.pointHighlightFill || dataset.pointColor,
|
||||
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
|
||||
});
|
||||
},this);
|
||||
|
||||
},this);
|
||||
|
||||
this.eachPoints(function(point){
|
||||
point.save();
|
||||
});
|
||||
this.reflow();
|
||||
this.render();
|
||||
},
|
||||
reflow: function(){
|
||||
helpers.extend(this.scale, {
|
||||
width : this.chart.width,
|
||||
height: this.chart.height,
|
||||
size : helpers.min([this.chart.width, this.chart.height]),
|
||||
xCenter: this.chart.width/2,
|
||||
yCenter: this.chart.height/2
|
||||
});
|
||||
this.updateScaleRange(this.datasets);
|
||||
this.scale.setScaleSize();
|
||||
this.scale.buildYLabels();
|
||||
},
|
||||
draw : function(ease){
|
||||
var easeDecimal = ease || 1,
|
||||
ctx = this.chart.ctx;
|
||||
this.clear();
|
||||
this.scale.draw();
|
||||
|
||||
helpers.each(this.datasets,function(dataset){
|
||||
|
||||
//Transition each point first so that the line and point drawing isn't out of sync
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
if (point.hasValue()){
|
||||
point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
|
||||
}
|
||||
},this);
|
||||
|
||||
|
||||
|
||||
//Draw the line between all the points
|
||||
ctx.lineWidth = this.options.datasetStrokeWidth;
|
||||
ctx.strokeStyle = dataset.strokeColor;
|
||||
ctx.beginPath();
|
||||
helpers.each(dataset.points,function(point,index){
|
||||
if (index === 0){
|
||||
ctx.moveTo(point.x,point.y);
|
||||
}
|
||||
else{
|
||||
ctx.lineTo(point.x,point.y);
|
||||
}
|
||||
},this);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.fillStyle = dataset.fillColor;
|
||||
ctx.fill();
|
||||
|
||||
//Now draw the points over the line
|
||||
//A little inefficient double looping, but better than the line
|
||||
//lagging behind the point positions
|
||||
helpers.each(dataset.points,function(point){
|
||||
if (point.hasValue()){
|
||||
point.draw();
|
||||
}
|
||||
});
|
||||
|
||||
},this);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,357 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
hover: {
|
||||
mode: "label"
|
||||
},
|
||||
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "category",
|
||||
categorySpacing: 10,
|
||||
spacing: 1,
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
offsetGridLines: true,
|
||||
},
|
||||
}],
|
||||
yAxes: [{
|
||||
type: "linear",
|
||||
}],
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
Chart.Type.extend({
|
||||
name: "Bar",
|
||||
defaults: defaultConfig,
|
||||
initialize: function() {
|
||||
|
||||
var _this = this;
|
||||
|
||||
// Events
|
||||
helpers.bindEvents(this, this.options.events, this.events);
|
||||
|
||||
//Create a new bar for each piece of data
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
dataset.metaData = [];
|
||||
helpers.each(dataset.data, function(dataPoint, index) {
|
||||
dataset.metaData.push(new Chart.Rectangle({
|
||||
_chart: this.chart,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
}));
|
||||
}, this);
|
||||
|
||||
// The bar chart only supports a single x axis because the x axis is always a dataset axis
|
||||
dataset.xAxisID = this.options.scales.xAxes[0].id;
|
||||
|
||||
if (!dataset.yAxisID) {
|
||||
dataset.yAxisID = this.options.scales.yAxes[0].id;
|
||||
}
|
||||
}, this);
|
||||
|
||||
// Build and fit the scale. Needs to happen after the axis IDs have been set
|
||||
this.buildScale();
|
||||
|
||||
// Create tooltip instance exclusively for this chart with some defaults.
|
||||
this.tooltip = new Chart.Tooltip({
|
||||
_chart: this.chart,
|
||||
_data: this.data,
|
||||
_options: this.options,
|
||||
}, this);
|
||||
|
||||
// Need to fit scales before we reset elements.
|
||||
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
|
||||
|
||||
// So that we animate from the baseline
|
||||
this.resetElements();
|
||||
|
||||
// Update the chart with the latest data.
|
||||
this.update();
|
||||
},
|
||||
resetElements: function() {
|
||||
// Update the points
|
||||
this.eachElement(function(bar, index, dataset, datasetIndex) {
|
||||
var xScale = this.scales[this.data.datasets[datasetIndex].xAxisID];
|
||||
var yScale = this.scales[this.data.datasets[datasetIndex].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(bar, {
|
||||
// Utility
|
||||
_chart: this.chart,
|
||||
_xScale: xScale,
|
||||
_yScale: yScale,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
x: xScale.calculateBarX(this.data.datasets.length, datasetIndex, index),
|
||||
y: yScalePoint,
|
||||
|
||||
// Appearance
|
||||
base: yScale.calculateBarBase(datasetIndex, index),
|
||||
width: xScale.calculateBarWidth(this.data.datasets.length),
|
||||
backgroundColor: bar.custom && bar.custom.backgroundColor ? bar.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].backgroundColor, index, this.options.elements.rectangle.backgroundColor),
|
||||
borderColor: bar.custom && bar.custom.borderColor ? bar.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].borderColor, index, this.options.elements.rectangle.borderColor),
|
||||
borderWidth: bar.custom && bar.custom.borderWidth ? bar.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].borderWidth, index, this.options.elements.rectangle.borderWidth),
|
||||
|
||||
// Tooltip
|
||||
label: this.data.labels[index],
|
||||
datasetLabel: this.data.datasets[datasetIndex].label,
|
||||
},
|
||||
});
|
||||
bar.pivot();
|
||||
}, this);
|
||||
},
|
||||
update: function(animationDuration) {
|
||||
// Update the scale sizes
|
||||
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
|
||||
|
||||
// Update the points
|
||||
this.eachElement(function(bar, index, dataset, datasetIndex) {
|
||||
var xScale = this.scales[this.data.datasets[datasetIndex].xAxisID];
|
||||
var yScale = this.scales[this.data.datasets[datasetIndex].yAxisID];
|
||||
|
||||
helpers.extend(bar, {
|
||||
// Utility
|
||||
_chart: this.chart,
|
||||
_xScale: xScale,
|
||||
_yScale: yScale,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
x: xScale.calculateBarX(this.data.datasets.length, datasetIndex, index),
|
||||
y: yScale.calculateBarY(datasetIndex, index),
|
||||
|
||||
// Appearance
|
||||
base: yScale.calculateBarBase(datasetIndex, index),
|
||||
width: xScale.calculateBarWidth(this.data.datasets.length),
|
||||
backgroundColor: bar.custom && bar.custom.backgroundColor ? bar.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].backgroundColor, index, this.options.elements.rectangle.backgroundColor),
|
||||
borderColor: bar.custom && bar.custom.borderColor ? bar.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].borderColor, index, this.options.elements.rectangle.borderColor),
|
||||
borderWidth: bar.custom && bar.custom.borderWidth ? bar.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].borderWidth, index, this.options.elements.rectangle.borderWidth),
|
||||
|
||||
// Tooltip
|
||||
label: this.data.labels[index],
|
||||
datasetLabel: this.data.datasets[datasetIndex].label,
|
||||
},
|
||||
});
|
||||
bar.pivot();
|
||||
}, this);
|
||||
|
||||
|
||||
this.render(animationDuration);
|
||||
},
|
||||
buildScale: function(labels) {
|
||||
var self = this;
|
||||
|
||||
// Map of scale ID to scale object so we can lookup later
|
||||
this.scales = {};
|
||||
|
||||
// Build the x axis. The line chart only supports a single x axis
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(this.options.scales.xAxes[0].type);
|
||||
var xScale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: this.options.scales.xAxes[0],
|
||||
id: this.options.scales.xAxes[0].id,
|
||||
data: this.data,
|
||||
});
|
||||
this.scales[xScale.id] = xScale;
|
||||
|
||||
// Build up all the y scales
|
||||
helpers.each(this.options.scales.yAxes, function(yAxisOptions) {
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(yAxisOptions.type);
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: yAxisOptions,
|
||||
data: this.data,
|
||||
id: yAxisOptions.id,
|
||||
});
|
||||
|
||||
this.scales[scale.id] = scale;
|
||||
}, this);
|
||||
},
|
||||
draw: function(ease) {
|
||||
|
||||
var easingDecimal = ease || 1;
|
||||
this.clear();
|
||||
|
||||
// Draw all the scales
|
||||
helpers.each(this.scales, function(scale) {
|
||||
scale.draw(this.chartArea);
|
||||
}, this);
|
||||
|
||||
//Draw all the bars for each dataset
|
||||
this.eachElement(function(bar, index, datasetIndex) {
|
||||
bar.transition(easingDecimal).draw();
|
||||
}, this);
|
||||
|
||||
// Finally draw the tooltip
|
||||
this.tooltip.transition(easingDecimal).draw();
|
||||
},
|
||||
events: function(e) {
|
||||
|
||||
|
||||
|
||||
this.lastActive = this.lastActive || [];
|
||||
|
||||
// Find Active Elements
|
||||
if (e.type == 'mouseout') {
|
||||
this.active = [];
|
||||
} else {
|
||||
this.active = function() {
|
||||
switch (this.options.hover.mode) {
|
||||
case 'single':
|
||||
return this.getElementAtEvent(e);
|
||||
case 'label':
|
||||
return this.getElementsAtEvent(e);
|
||||
case 'dataset':
|
||||
return this.getDatasetAtEvent(e);
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
}.call(this);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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':
|
||||
dataset = this.data.datasets[this.lastActive[0]._datasetIndex];
|
||||
index = this.lastActive[0]._index;
|
||||
|
||||
this.lastActive[0]._model.backgroundColor = this.lastActive[0].custom && this.lastActive[0].custom.backgroundColor ? this.lastActive[0].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, this.options.elements.rectangle.backgroundColor);
|
||||
this.lastActive[0]._model.borderColor = this.lastActive[0].custom && this.lastActive[0].custom.borderColor ? this.lastActive[0].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, this.options.elements.rectangle.borderColor);
|
||||
this.lastActive[0]._model.borderWidth = this.lastActive[0].custom && this.lastActive[0].custom.borderWidth ? this.lastActive[0].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.options.elements.rectangle.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.lastActive.length; i++) {
|
||||
dataset = this.data.datasets[this.lastActive[i]._datasetIndex];
|
||||
index = this.lastActive[i]._index;
|
||||
|
||||
this.lastActive[i]._model.backgroundColor = this.lastActive[i].custom && this.lastActive[i].custom.backgroundColor ? this.lastActive[i].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, this.options.elements.rectangle.backgroundColor);
|
||||
this.lastActive[i]._model.borderColor = this.lastActive[i].custom && this.lastActive[i].custom.borderColor ? this.lastActive[i].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, this.options.elements.rectangle.borderColor);
|
||||
this.lastActive[i]._model.borderWidth = this.lastActive[i].custom && this.lastActive[i].custom.borderWidth ? this.lastActive[i].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.options.elements.rectangle.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
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':
|
||||
dataset = this.data.datasets[this.active[0]._datasetIndex];
|
||||
index = this.active[0]._index;
|
||||
|
||||
this.active[0]._model.backgroundColor = this.active[0].custom && this.active[0].custom.hoverBackgroundColor ? this.active[0].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(this.active[0]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderColor = this.active[0].custom && this.active[0].custom.hoverBorderColor ? this.active[0].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(this.active[0]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderWidth = this.active[0].custom && this.active[0].custom.hoverBorderWidth ? this.active[0].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.active[0]._model.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.active.length; i++) {
|
||||
dataset = this.data.datasets[this.active[i]._datasetIndex];
|
||||
index = this.active[i]._index;
|
||||
|
||||
this.active[i]._model.backgroundColor = this.active[i].custom && this.active[i].custom.hoverBackgroundColor ? this.active[i].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(this.active[i]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderColor = this.active[i].custom && this.active[i].custom.hoverBorderColor ? this.active[i].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(this.active[i]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderWidth = this.active[i].custom && this.active[i].custom.hoverBorderWidth ? this.active[i].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.active[i]._model.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
break;
|
||||
default:
|
||||
// Don't change anything
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Built in Tooltips
|
||||
if (this.options.tooltips.enabled) {
|
||||
|
||||
// The usual updates
|
||||
this.tooltip.initialize();
|
||||
|
||||
// Active
|
||||
if (this.active.length) {
|
||||
this.tooltip._model.opacity = 1;
|
||||
|
||||
helpers.extend(this.tooltip, {
|
||||
_active: this.active,
|
||||
});
|
||||
|
||||
this.tooltip.update();
|
||||
} else {
|
||||
// Inactive
|
||||
this.tooltip._model.opacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.tooltip.pivot();
|
||||
|
||||
// Hover animations
|
||||
if (!this.animating) {
|
||||
var changed;
|
||||
|
||||
helpers.each(this.active, function(element, index) {
|
||||
if (element !== this.lastActive[index]) {
|
||||
changed = true;
|
||||
}
|
||||
}, this);
|
||||
|
||||
// If entering, leaving, or changing elements, animate the change via pivot
|
||||
if ((!this.lastActive.length && this.active.length) ||
|
||||
(this.lastActive.length && !this.active.length) ||
|
||||
(this.lastActive.length && this.active.length && changed)) {
|
||||
|
||||
this.stop();
|
||||
this.render(this.options.hoverAnimationDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// Remember Last Active
|
||||
this.lastActive = this.active;
|
||||
return this;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,365 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
//Cache a local reference to Chart.helpers
|
||||
helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
|
||||
animation: {
|
||||
//Boolean - Whether we animate the rotation of the Doughnut
|
||||
animateRotate: true,
|
||||
|
||||
//Boolean - Whether we animate scaling the Doughnut from the centre
|
||||
animateScale: false,
|
||||
},
|
||||
|
||||
hover: {
|
||||
mode: 'single'
|
||||
},
|
||||
|
||||
//The percentage of the chart that we cut out of the middle.
|
||||
|
||||
cutoutPercentage: 50,
|
||||
|
||||
};
|
||||
|
||||
Chart.Type.extend({
|
||||
//Passing in a name registers this chart in the Chart namespace
|
||||
name: "Doughnut",
|
||||
//Providing a defaults will also register the deafults in the chart namespace
|
||||
defaults: defaultConfig,
|
||||
//Initialize is fired when the chart is initialized - Data is passed in as a parameter
|
||||
//Config is automatically merged by the core of Chart.js, and is available at this.options
|
||||
initialize: function() {
|
||||
|
||||
//Set up tooltip events on the chart
|
||||
helpers.bindEvents(this, this.options.events, this.events);
|
||||
|
||||
//Create a new bar for each piece of data
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
dataset.metaData = [];
|
||||
helpers.each(dataset.data, function(dataPoint, index) {
|
||||
dataset.metaData.push(new Chart.Arc({
|
||||
_chart: this.chart,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
_model: {}
|
||||
}));
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
// Create tooltip instance exclusively for this chart with some defaults.
|
||||
this.tooltip = new Chart.Tooltip({
|
||||
_chart: this.chart,
|
||||
_data: this.data,
|
||||
_options: this.options,
|
||||
}, this);
|
||||
|
||||
this.resetElements();
|
||||
|
||||
// Update the chart with the latest data.
|
||||
this.update();
|
||||
|
||||
},
|
||||
|
||||
calculateCircumference: function(dataset, value) {
|
||||
if (dataset.total > 0) {
|
||||
return (Math.PI * 2) * (value / dataset.total);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
resetElements: function() {
|
||||
this.outerRadius = (helpers.min([this.chart.width, this.chart.height]) - this.options.elements.arc.borderWidth / 2) / 2;
|
||||
this.innerRadius = this.options.cutoutPercentage ? (this.outerRadius / 100) * (this.options.cutoutPercentage) : 1;
|
||||
this.radiusLength = (this.outerRadius - this.innerRadius) / this.data.datasets.length;
|
||||
|
||||
// Update the points
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
// So that calculateCircumference works
|
||||
dataset.total = 0;
|
||||
helpers.each(dataset.data, function(value) {
|
||||
dataset.total += Math.abs(value);
|
||||
}, this);
|
||||
|
||||
dataset.outerRadius = this.outerRadius - (this.radiusLength * datasetIndex);
|
||||
dataset.innerRadius = dataset.outerRadius - this.radiusLength;
|
||||
|
||||
helpers.each(dataset.metaData, function(slice, index) {
|
||||
helpers.extend(slice, {
|
||||
_model: {
|
||||
x: this.chart.width / 2,
|
||||
y: this.chart.height / 2,
|
||||
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
|
||||
circumference: (this.options.animation.animateRotate) ? 0 : this.calculateCircumference(metaSlice.value),
|
||||
outerRadius: (this.options.animation.animateScale) ? 0 : dataset.outerRadius,
|
||||
innerRadius: (this.options.animation.animateScale) ? 0 : dataset.innerRadius,
|
||||
|
||||
backgroundColor: slice.custom && slice.custom.backgroundColor ? slice.custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, this.options.elements.arc.backgroundColor),
|
||||
hoverBackgroundColor: slice.custom && slice.custom.hoverBackgroundColor ? slice.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, this.options.elements.arc.hoverBackgroundColor),
|
||||
borderWidth: slice.custom && slice.custom.borderWidth ? slice.custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.options.elements.arc.borderWidth),
|
||||
borderColor: slice.custom && slice.custom.borderColor ? slice.custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, this.options.elements.arc.borderColor),
|
||||
|
||||
label: helpers.getValueAtIndexOrDefault(dataset.label, index, this.data.labels[index])
|
||||
},
|
||||
});
|
||||
|
||||
slice.pivot();
|
||||
}, this);
|
||||
|
||||
}, this);
|
||||
},
|
||||
update: function(animationDuration) {
|
||||
|
||||
this.outerRadius = (helpers.min([this.chart.width, this.chart.height]) - this.options.elements.arc.borderWidth / 2) / 2;
|
||||
this.innerRadius = this.options.cutoutPercentage ? (this.outerRadius / 100) * (this.options.cutoutPercentage) : 1;
|
||||
this.radiusLength = (this.outerRadius - this.innerRadius) / this.data.datasets.length;
|
||||
|
||||
|
||||
// Update the points
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
|
||||
dataset.total = 0;
|
||||
helpers.each(dataset.data, function(value) {
|
||||
dataset.total += Math.abs(value);
|
||||
}, this);
|
||||
|
||||
|
||||
dataset.outerRadius = this.outerRadius - (this.radiusLength * datasetIndex);
|
||||
|
||||
dataset.innerRadius = dataset.outerRadius - this.radiusLength;
|
||||
|
||||
helpers.each(dataset.metaData, function(slice, index) {
|
||||
|
||||
helpers.extend(slice, {
|
||||
// Utility
|
||||
_chart: this.chart,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
x: this.chart.width / 2,
|
||||
y: this.chart.height / 2,
|
||||
circumference: this.calculateCircumference(dataset, dataset.data[index]),
|
||||
outerRadius: dataset.outerRadius,
|
||||
innerRadius: dataset.innerRadius,
|
||||
|
||||
backgroundColor: slice.custom && slice.custom.backgroundColor ? slice.custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, this.options.elements.arc.backgroundColor),
|
||||
hoverBackgroundColor: slice.custom && slice.custom.hoverBackgroundColor ? slice.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, this.options.elements.arc.hoverBackgroundColor),
|
||||
borderWidth: slice.custom && slice.custom.borderWidth ? slice.custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.options.elements.arc.borderWidth),
|
||||
borderColor: slice.custom && slice.custom.borderColor ? slice.custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, this.options.elements.arc.borderColor),
|
||||
|
||||
label: helpers.getValueAtIndexOrDefault(dataset.label, index, this.data.labels[index])
|
||||
},
|
||||
});
|
||||
|
||||
if (index === 0) {
|
||||
slice._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 {
|
||||
slice._model.startAngle = dataset.metaData[index - 1]._model.endAngle;
|
||||
}
|
||||
|
||||
slice._model.endAngle = slice._model.startAngle + slice._model.circumference;
|
||||
|
||||
|
||||
//Check to see if it's the last slice, if not get the next and update its start angle
|
||||
if (index < dataset.data.length - 1) {
|
||||
dataset.metaData[index + 1]._model.startAngle = slice._model.endAngle;
|
||||
}
|
||||
|
||||
slice.pivot();
|
||||
}, this);
|
||||
|
||||
}, this);
|
||||
|
||||
this.render(animationDuration);
|
||||
},
|
||||
draw: function(easeDecimal) {
|
||||
easeDecimal = easeDecimal || 1;
|
||||
this.clear();
|
||||
|
||||
this.eachElement(function(slice) {
|
||||
slice.transition(easeDecimal).draw();
|
||||
}, this);
|
||||
|
||||
this.tooltip.transition(easeDecimal).draw();
|
||||
},
|
||||
events: function(e) {
|
||||
|
||||
this.lastActive = this.lastActive || [];
|
||||
|
||||
// Find Active Elements
|
||||
if (e.type == 'mouseout') {
|
||||
this.active = [];
|
||||
} else {
|
||||
|
||||
this.active = function() {
|
||||
switch (this.options.hover.mode) {
|
||||
case 'single':
|
||||
return this.getSliceAtEvent(e);
|
||||
case 'label':
|
||||
return this.getSlicesAtEvent(e);
|
||||
case 'dataset':
|
||||
return this.getDatasetAtEvent(e);
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
}.call(this);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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':
|
||||
dataset = this.data.datasets[this.lastActive[0]._datasetIndex];
|
||||
index = this.lastActive[0]._index;
|
||||
|
||||
this.lastActive[0]._model.backgroundColor = this.lastActive[0].custom && this.lastActive[0].custom.backgroundColor ? this.lastActive[0].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, this.options.elements.arc.backgroundColor);
|
||||
this.lastActive[0]._model.borderColor = this.lastActive[0].custom && this.lastActive[0].custom.borderColor ? this.lastActive[0].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, this.options.elements.arc.borderColor);
|
||||
this.lastActive[0]._model.borderWidth = this.lastActive[0].custom && this.lastActive[0].custom.borderWidth ? this.lastActive[0].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.options.elements.arc.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.lastActive.length; i++) {
|
||||
dataset = this.data.datasets[this.lastActive[i]._datasetIndex];
|
||||
index = this.lastActive[i]._index;
|
||||
|
||||
this.lastActive[i]._model.backgroundColor = this.lastActive[i].custom && this.lastActive[i].custom.backgroundColor ? this.lastActive[i].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, this.options.elements.arc.backgroundColor);
|
||||
this.lastActive[i]._model.borderColor = this.lastActive[i].custom && this.lastActive[i].custom.borderColor ? this.lastActive[i].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, this.options.elements.arc.borderColor);
|
||||
this.lastActive[i]._model.borderWidth = this.lastActive[i].custom && this.lastActive[i].custom.borderWidth ? this.lastActive[i].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.options.elements.arc.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
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':
|
||||
dataset = this.data.datasets[this.active[0]._datasetIndex];
|
||||
index = this.active[0]._index;
|
||||
|
||||
this.active[0]._model.backgroundColor = this.active[0].custom && this.active[0].custom.hoverBackgroundColor ? this.active[0].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(this.active[0]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderColor = this.active[0].custom && this.active[0].custom.hoverBorderColor ? this.active[0].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, this.active[0]._model.borderColor);
|
||||
this.active[0]._model.borderWidth = this.active[0].custom && this.active[0].custom.hoverBorderWidth ? this.active[0].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, this.active[0]._model.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.active.length; i++) {
|
||||
dataset = this.data.datasets[this.active[i]._datasetIndex];
|
||||
index = this.active[i]._index;
|
||||
|
||||
this.active[i]._model.backgroundColor = this.active[i].custom && this.active[i].custom.hoverBackgroundColor ? this.active[i].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(this.active[i]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderColor = this.active[i].custom && this.active[i].custom.hoverBorderColor ? this.active[i].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, this.active[0]._model.borderColor);
|
||||
this.active[i]._model.borderWidth = this.active[i].custom && this.active[i].custom.hoverBorderWidth ? this.active[i].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, this.active[i]._model.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
break;
|
||||
default:
|
||||
// Don't change anything
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Built in Tooltips
|
||||
if (this.options.tooltips.enabled) {
|
||||
|
||||
// The usual updates
|
||||
this.tooltip.initialize();
|
||||
|
||||
// Active
|
||||
if (this.active.length) {
|
||||
this.tooltip._model.opacity = 1;
|
||||
|
||||
helpers.extend(this.tooltip, {
|
||||
_active: this.active,
|
||||
});
|
||||
|
||||
this.tooltip.update();
|
||||
} else {
|
||||
// Inactive
|
||||
this.tooltip._model.opacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// If entering, leaving, or changing elements, animate the change via pivot
|
||||
if ((!this.lastActive.length && this.active.length) ||
|
||||
(this.lastActive.length && !this.active.length) ||
|
||||
(this.lastActive.length && this.active.length && changed)) {
|
||||
|
||||
this.stop();
|
||||
this.render(this.options.hover.animationDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// Remember Last Active
|
||||
this.lastActive = this.active;
|
||||
return this;
|
||||
},
|
||||
getSliceAtEvent: function(e) {
|
||||
var elements = [];
|
||||
|
||||
var location = helpers.getRelativePosition(e);
|
||||
|
||||
this.eachElement(function(slice, index) {
|
||||
if (slice.inRange(location.x, location.y)) {
|
||||
elements.push(slice);
|
||||
}
|
||||
}, this);
|
||||
return elements;
|
||||
},
|
||||
/*getSlicesAtEvent: function(e) {
|
||||
var elements = [];
|
||||
|
||||
var location = helpers.getRelativePosition(e);
|
||||
|
||||
this.eachElement(function(slice, index) {
|
||||
if (slice.inGroupRange(location.x, location.y)) {
|
||||
elements.push(slice);
|
||||
}
|
||||
}, this);
|
||||
return elements;
|
||||
},*/
|
||||
});
|
||||
|
||||
Chart.types.Doughnut.extend({
|
||||
name: "Pie",
|
||||
defaults: helpers.merge(defaultConfig, {
|
||||
cutoutPercentage: 0
|
||||
})
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,497 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
hover: {
|
||||
mode: "label"
|
||||
},
|
||||
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "category",
|
||||
}],
|
||||
yAxes: [{
|
||||
type: "linear",
|
||||
}],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Chart.Type.extend({
|
||||
name: "Line",
|
||||
defaults: defaultConfig,
|
||||
initialize: function() {
|
||||
|
||||
var _this = this;
|
||||
|
||||
// Events
|
||||
helpers.bindEvents(this, this.options.events, this.events);
|
||||
|
||||
// Create a new line and its points for each dataset and piece of data
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
|
||||
dataset.metaDataset = new Chart.Line({
|
||||
_chart: this.chart,
|
||||
_datasetIndex: datasetIndex,
|
||||
_points: dataset.metaData,
|
||||
});
|
||||
|
||||
dataset.metaData = [];
|
||||
|
||||
helpers.each(dataset.data, function(dataPoint, index) {
|
||||
dataset.metaData.push(new Chart.Point({
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
_chart: this.chart,
|
||||
_model: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
}, this);
|
||||
|
||||
// The line chart onlty supports a single x axis because the x axis is always a dataset axis
|
||||
if (!dataset.xAxisID) {
|
||||
dataset.xAxisID = this.options.scales.xAxes[0].id;
|
||||
}
|
||||
|
||||
if (!dataset.yAxisID) {
|
||||
dataset.yAxisID = this.options.scales.yAxes[0].id;
|
||||
}
|
||||
|
||||
}, this);
|
||||
|
||||
// Build and fit the scale. Needs to happen after the axis IDs have been set
|
||||
this.buildScale();
|
||||
|
||||
// Create tooltip instance exclusively for this chart with some defaults.
|
||||
this.tooltip = new Chart.Tooltip({
|
||||
_chart: this.chart,
|
||||
_data: this.data,
|
||||
_options: this.options,
|
||||
}, this);
|
||||
|
||||
// Need to fit scales before we reset elements.
|
||||
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
|
||||
|
||||
// Reset so that we animation from the baseline
|
||||
this.resetElements();
|
||||
|
||||
// Update that shiz
|
||||
this.update();
|
||||
},
|
||||
nextPoint: function(collection, index) {
|
||||
return collection[index + 1] || collection[index];
|
||||
},
|
||||
previousPoint: function(collection, index) {
|
||||
return collection[index - 1] || collection[index];
|
||||
},
|
||||
resetElements: function() {
|
||||
// Update the points
|
||||
this.eachElement(function(point, index, dataset, datasetIndex) {
|
||||
var xScale = this.scales[this.data.datasets[datasetIndex].xAxisID];
|
||||
var yScale = this.scales[this.data.datasets[datasetIndex].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(point, {
|
||||
// Utility
|
||||
_chart: this.chart,
|
||||
_xScale: xScale,
|
||||
_yScale: yScale,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
x: xScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
|
||||
y: yScalePoint,
|
||||
|
||||
// Appearance
|
||||
tension: point.custom && point.custom.tension ? point.custom.tension : this.options.elements.line.tension,
|
||||
radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].radius, index, this.options.elements.point.radius),
|
||||
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBackgroundColor, index, this.options.elements.point.backgroundColor),
|
||||
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderColor, index, this.options.elements.point.borderColor),
|
||||
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderWidth, index, this.options.elements.point.borderWidth),
|
||||
skip: this.data.datasets[datasetIndex].data[index] === null,
|
||||
|
||||
// Tooltip
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].hitRadius, index, this.options.elements.point.hitRadius),
|
||||
},
|
||||
});
|
||||
}, this);
|
||||
|
||||
// Update control points for the bezier curve
|
||||
this.eachElement(function(point, index, dataset, datasetIndex) {
|
||||
var controlPoints = helpers.splineCurve(
|
||||
this.previousPoint(dataset, index)._model,
|
||||
point._model,
|
||||
this.nextPoint(dataset, index)._model,
|
||||
point._model.tension
|
||||
);
|
||||
|
||||
point._model.controlPointPreviousX = controlPoints.previous.x;
|
||||
point._model.controlPointNextX = controlPoints.next.x;
|
||||
|
||||
// Prevent the bezier going outside of the bounds of the graph
|
||||
|
||||
// Cap puter bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.next.y > this.chartArea.bottom) {
|
||||
point._model.controlPointNextY = this.chartArea.bottom;
|
||||
} else if (controlPoints.next.y < this.chartArea.top) {
|
||||
point._model.controlPointNextY = this.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointNextY = controlPoints.next.y;
|
||||
}
|
||||
|
||||
// Cap inner bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.previous.y > this.chartArea.bottom) {
|
||||
point._model.controlPointPreviousY = this.chartArea.bottom;
|
||||
} else if (controlPoints.previous.y < this.chartArea.top) {
|
||||
point._model.controlPointPreviousY = this.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointPreviousY = controlPoints.previous.y;
|
||||
}
|
||||
|
||||
// Now pivot the point for animation
|
||||
point.pivot();
|
||||
}, this);
|
||||
},
|
||||
update: function(animationDuration) {
|
||||
|
||||
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
|
||||
|
||||
// Update the lines
|
||||
this.eachDataset(function(dataset, datasetIndex) {
|
||||
var yScale = this.scales[dataset.yAxisID];
|
||||
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(dataset.metaDataset, {
|
||||
// Utility
|
||||
_scale: yScale,
|
||||
_datasetIndex: datasetIndex,
|
||||
// Data
|
||||
_children: dataset.metaData,
|
||||
// Model
|
||||
_model: {
|
||||
// Appearance
|
||||
tension: dataset.metaDataset.custom && dataset.metaDataset.custom.tension ? dataset.metaDataset.custom.tension : (dataset.tension || this.options.elements.line.tension),
|
||||
backgroundColor: dataset.metaDataset.custom && dataset.metaDataset.custom.backgroundColor ? dataset.metaDataset.custom.backgroundColor : (dataset.backgroundColor || this.options.elements.line.backgroundColor),
|
||||
borderWidth: dataset.metaDataset.custom && dataset.metaDataset.custom.borderWidth ? dataset.metaDataset.custom.borderWidth : (dataset.borderWidth || this.options.elements.line.borderWidth),
|
||||
borderColor: dataset.metaDataset.custom && dataset.metaDataset.custom.borderColor ? dataset.metaDataset.custom.borderColor : (dataset.borderColor || this.options.elements.line.borderColor),
|
||||
fill: dataset.metaDataset.custom && dataset.metaDataset.custom.fill ? dataset.metaDataset.custom.fill : (dataset.fill !== undefined ? dataset.fill : this.options.elements.line.fill),
|
||||
skipNull: dataset.skipNull !== undefined ? dataset.skipNull : this.options.elements.line.skipNull,
|
||||
drawNull: dataset.drawNull !== undefined ? dataset.drawNull : this.options.elements.line.drawNull,
|
||||
// Scale
|
||||
scaleTop: yScale.top,
|
||||
scaleBottom: yScale.bottom,
|
||||
scaleZero: scaleBase,
|
||||
},
|
||||
});
|
||||
|
||||
dataset.metaDataset.pivot();
|
||||
});
|
||||
|
||||
// Update the points
|
||||
this.eachElement(function(point, index, dataset, datasetIndex) {
|
||||
var xScale = this.scales[this.data.datasets[datasetIndex].xAxisID];
|
||||
var yScale = this.scales[this.data.datasets[datasetIndex].yAxisID];
|
||||
|
||||
helpers.extend(point, {
|
||||
// Utility
|
||||
_chart: this.chart,
|
||||
_xScale: xScale,
|
||||
_yScale: yScale,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
x: xScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
|
||||
y: yScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
|
||||
|
||||
// Appearance
|
||||
tension: point.custom && point.custom.tension ? point.custom.tension : this.options.elements.line.tension,
|
||||
radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].radius, index, this.options.elements.point.radius),
|
||||
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBackgroundColor, index, this.options.elements.point.backgroundColor),
|
||||
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderColor, index, this.options.elements.point.borderColor),
|
||||
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderWidth, index, this.options.elements.point.borderWidth),
|
||||
skip: this.data.datasets[datasetIndex].data[index] === null,
|
||||
|
||||
// Tooltip
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].hitRadius, index, this.options.elements.point.hitRadius),
|
||||
},
|
||||
});
|
||||
}, this);
|
||||
|
||||
|
||||
// Update control points for the bezier curve
|
||||
this.eachElement(function(point, index, dataset, datasetIndex) {
|
||||
var controlPoints = helpers.splineCurve(
|
||||
this.previousPoint(dataset, index)._model,
|
||||
point._model,
|
||||
this.nextPoint(dataset, index)._model,
|
||||
point._model.tension
|
||||
);
|
||||
|
||||
point._model.controlPointPreviousX = controlPoints.previous.x;
|
||||
point._model.controlPointNextX = controlPoints.next.x;
|
||||
|
||||
// Prevent the bezier going outside of the bounds of the graph
|
||||
|
||||
// Cap puter bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.next.y > this.chartArea.bottom) {
|
||||
point._model.controlPointNextY = this.chartArea.bottom;
|
||||
} else if (controlPoints.next.y < this.chartArea.top) {
|
||||
point._model.controlPointNextY = this.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointNextY = controlPoints.next.y;
|
||||
}
|
||||
|
||||
// Cap inner bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.previous.y > this.chartArea.bottom) {
|
||||
point._model.controlPointPreviousY = this.chartArea.bottom;
|
||||
} else if (controlPoints.previous.y < this.chartArea.top) {
|
||||
point._model.controlPointPreviousY = this.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointPreviousY = controlPoints.previous.y;
|
||||
}
|
||||
|
||||
// Now pivot the point for animation
|
||||
point.pivot();
|
||||
}, this);
|
||||
|
||||
this.render(animationDuration);
|
||||
},
|
||||
buildScale: function() {
|
||||
// Map of scale ID to scale object so we can lookup later
|
||||
this.scales = {};
|
||||
|
||||
// Build the x axes
|
||||
helpers.each(this.options.scales.xAxes, function(xAxisOptions) {
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(xAxisOptions.type);
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: xAxisOptions,
|
||||
data: this.data,
|
||||
id: xAxisOptions.id,
|
||||
});
|
||||
|
||||
this.scales[scale.id] = scale;
|
||||
}, this);
|
||||
|
||||
// Build the y axes
|
||||
helpers.each(this.options.scales.yAxes, function(yAxisOptions) {
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(yAxisOptions.type);
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: yAxisOptions,
|
||||
data: this.data,
|
||||
id: yAxisOptions.id,
|
||||
});
|
||||
|
||||
this.scales[scale.id] = scale;
|
||||
}, this);
|
||||
},
|
||||
draw: function(ease) {
|
||||
|
||||
var easingDecimal = ease || 1;
|
||||
this.clear();
|
||||
|
||||
// Draw all the scales
|
||||
helpers.each(this.scales, function(scale) {
|
||||
scale.draw(this.chartArea);
|
||||
}, this);
|
||||
|
||||
// reverse for-loop for proper stacking
|
||||
for (var i = this.data.datasets.length - 1; i >= 0; i--) {
|
||||
|
||||
var dataset = this.data.datasets[i];
|
||||
|
||||
// Transition Point Locations
|
||||
helpers.each(dataset.metaData, function(point, index) {
|
||||
point.transition(easingDecimal);
|
||||
}, this);
|
||||
|
||||
// Transition and Draw the line
|
||||
dataset.metaDataset.transition(easingDecimal).draw();
|
||||
|
||||
// Draw the points
|
||||
helpers.each(dataset.metaData, function(point) {
|
||||
point.draw();
|
||||
});
|
||||
}
|
||||
|
||||
// Finally draw the tooltip
|
||||
this.tooltip.transition(easingDecimal).draw();
|
||||
},
|
||||
events: function(e) {
|
||||
|
||||
this.lastActive = this.lastActive || [];
|
||||
|
||||
// Find Active Elements
|
||||
if (e.type == 'mouseout') {
|
||||
this.active = [];
|
||||
} else {
|
||||
this.active = function() {
|
||||
switch (this.options.hover.mode) {
|
||||
case 'single':
|
||||
return this.getElementAtEvent(e);
|
||||
case 'label':
|
||||
return this.getElementsAtEvent(e);
|
||||
case 'dataset':
|
||||
return this.getDatasetAtEvent(e);
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
}.call(this);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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':
|
||||
dataset = this.data.datasets[this.lastActive[0]._datasetIndex];
|
||||
index = this.lastActive[0]._index;
|
||||
|
||||
this.lastActive[0]._model.radius = this.lastActive[0].custom && this.lastActive[0].custom.radius ? this.lastActive[0].custom.radius : helpers.getValueAtIndexOrDefault(dataset.radius, index, this.options.elements.point.radius);
|
||||
this.lastActive[0]._model.backgroundColor = this.lastActive[0].custom && this.lastActive[0].custom.backgroundColor ? this.lastActive[0].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, this.options.elements.point.backgroundColor);
|
||||
this.lastActive[0]._model.borderColor = this.lastActive[0].custom && this.lastActive[0].custom.borderColor ? this.lastActive[0].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, this.options.elements.point.borderColor);
|
||||
this.lastActive[0]._model.borderWidth = this.lastActive[0].custom && this.lastActive[0].custom.borderWidth ? this.lastActive[0].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.options.elements.point.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.lastActive.length; i++) {
|
||||
dataset = this.data.datasets[this.lastActive[i]._datasetIndex];
|
||||
index = this.lastActive[i]._index;
|
||||
|
||||
this.lastActive[i]._model.radius = this.lastActive[i].custom && this.lastActive[i].custom.radius ? this.lastActive[i].custom.radius : helpers.getValueAtIndexOrDefault(dataset.radius, index, this.options.elements.point.radius);
|
||||
this.lastActive[i]._model.backgroundColor = this.lastActive[i].custom && this.lastActive[i].custom.backgroundColor ? this.lastActive[i].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, this.options.elements.point.backgroundColor);
|
||||
this.lastActive[i]._model.borderColor = this.lastActive[i].custom && this.lastActive[i].custom.borderColor ? this.lastActive[i].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, this.options.elements.point.borderColor);
|
||||
this.lastActive[i]._model.borderWidth = this.lastActive[i].custom && this.lastActive[i].custom.borderWidth ? this.lastActive[i].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.options.elements.point.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
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':
|
||||
dataset = this.data.datasets[this.active[0]._datasetIndex];
|
||||
index = this.active[0]._index;
|
||||
|
||||
this.active[0]._model.radius = this.active[0].custom && this.active[0].custom.radius ? this.active[0].custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.options.elements.point.hoverRadius);
|
||||
this.active[0]._model.backgroundColor = this.active[0].custom && this.active[0].custom.hoverBackgroundColor ? this.active[0].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[0]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderColor = this.active[0].custom && this.active[0].custom.hoverBorderColor ? this.active[0].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[0]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderWidth = this.active[0].custom && this.active[0].custom.hoverBorderWidth ? this.active[0].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[0]._model.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.active.length; i++) {
|
||||
dataset = this.data.datasets[this.active[i]._datasetIndex];
|
||||
index = this.active[i]._index;
|
||||
|
||||
this.active[i]._model.radius = this.active[i].custom && this.active[i].custom.radius ? this.active[i].custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.options.elements.point.hoverRadius);
|
||||
this.active[i]._model.backgroundColor = this.active[i].custom && this.active[i].custom.hoverBackgroundColor ? this.active[i].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[i]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderColor = this.active[i].custom && this.active[i].custom.hoverBorderColor ? this.active[i].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[i]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderWidth = this.active[i].custom && this.active[i].custom.hoverBorderWidth ? this.active[i].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[i]._model.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
break;
|
||||
default:
|
||||
// Don't change anything
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Built in Tooltips
|
||||
if (this.options.tooltips.enabled) {
|
||||
|
||||
// The usual updates
|
||||
this.tooltip.initialize();
|
||||
|
||||
// Active
|
||||
if (this.active.length) {
|
||||
this.tooltip._model.opacity = 1;
|
||||
|
||||
helpers.extend(this.tooltip, {
|
||||
_active: this.active,
|
||||
});
|
||||
|
||||
this.tooltip.update();
|
||||
} else {
|
||||
// Inactive
|
||||
this.tooltip._model.opacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// If entering, leaving, or changing elements, animate the change via pivot
|
||||
if ((!this.lastActive.length && this.active.length) ||
|
||||
(this.lastActive.length && !this.active.length) ||
|
||||
(this.lastActive.length && this.active.length && changed)) {
|
||||
|
||||
this.stop();
|
||||
this.render(this.options.hover.animationDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// Remember Last Active
|
||||
this.lastActive = this.active;
|
||||
return this;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,346 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
//Cache a local reference to Chart.helpers
|
||||
helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
|
||||
scale: {
|
||||
type: "radialLinear",
|
||||
lineArc: true, // so that lines are circular
|
||||
},
|
||||
|
||||
//Boolean - Whether to animate the rotation of the chart
|
||||
animateRotate: true,
|
||||
};
|
||||
|
||||
|
||||
Chart.Type.extend({
|
||||
//Passing in a name registers this chart in the Chart namespace
|
||||
name: "PolarArea",
|
||||
//Providing a defaults will also register the deafults in the chart namespace
|
||||
defaults: defaultConfig,
|
||||
//Initialize is fired when the chart is initialized - Data is passed in as a parameter
|
||||
//Config is automatically merged by the core of Chart.js, and is available at this.options
|
||||
initialize: function() {
|
||||
|
||||
// Scale setup
|
||||
var self = this;
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(this.options.scale.type);
|
||||
this.scale = new ScaleClass({
|
||||
options: this.options.scale,
|
||||
lineArc: true,
|
||||
width: this.chart.width,
|
||||
height: this.chart.height,
|
||||
xCenter: this.chart.width / 2,
|
||||
yCenter: this.chart.height / 2,
|
||||
ctx: this.chart.ctx,
|
||||
valuesCount: this.data.length,
|
||||
data: this.data
|
||||
});
|
||||
|
||||
helpers.bindEvents(this, this.options.events, this.events);
|
||||
|
||||
//Set up tooltip events on the chart
|
||||
helpers.bindEvents(this, this.options.events, this.events);
|
||||
|
||||
//Create a new bar for each piece of data
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
dataset.metaData = [];
|
||||
helpers.each(dataset.data, function(dataPoint, index) {
|
||||
dataset.metaData.push(new Chart.Arc({
|
||||
_chart: this.chart,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
_model: {}
|
||||
}));
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
// Create tooltip instance exclusively for this chart with some defaults.
|
||||
this.tooltip = new Chart.Tooltip({
|
||||
_chart: this.chart,
|
||||
_data: this.data,
|
||||
_options: this.options,
|
||||
}, this);
|
||||
|
||||
// Fit the scale before we animate
|
||||
this.updateScaleRange();
|
||||
this.scale.calculateRange();
|
||||
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
|
||||
|
||||
// so that we animate nicely
|
||||
this.resetElements();
|
||||
|
||||
// Update the chart with the latest data.
|
||||
this.update();
|
||||
|
||||
},
|
||||
updateScaleRange: function() {
|
||||
helpers.extend(this.scale, {
|
||||
size: helpers.min([this.chart.width, this.chart.height]),
|
||||
xCenter: this.chart.width / 2,
|
||||
yCenter: this.chart.height / 2
|
||||
});
|
||||
},
|
||||
resetElements: function() {
|
||||
var circumference = 1 / this.data.datasets[0].data.length * 2;
|
||||
|
||||
// Map new data to data points
|
||||
helpers.each(this.data.datasets[0].metaData, function(slice, index) {
|
||||
|
||||
var value = this.data.datasets[0].data[index];
|
||||
|
||||
helpers.extend(slice, {
|
||||
_index: index,
|
||||
_model: {
|
||||
x: this.chart.width / 2,
|
||||
y: this.chart.height / 2,
|
||||
innerRadius: 0,
|
||||
outerRadius: 0,
|
||||
startAngle: Math.PI * -0.5,
|
||||
endAngle: Math.PI * -0.5,
|
||||
|
||||
backgroundColor: slice.custom && slice.custom.backgroundColor ? slice.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[0].backgroundColor, index, this.options.elements.arc.backgroundColor),
|
||||
hoverBackgroundColor: slice.custom && slice.custom.hoverBackgroundColor ? slice.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[0].hoverBackgroundColor, index, this.options.elements.arc.hoverBackgroundColor),
|
||||
borderWidth: slice.custom && slice.custom.borderWidth ? slice.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[0].borderWidth, index, this.options.elements.arc.borderWidth),
|
||||
borderColor: slice.custom && slice.custom.borderColor ? slice.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[0].borderColor, index, this.options.elements.arc.borderColor),
|
||||
|
||||
label: helpers.getValueAtIndexOrDefault(this.data.datasets[0].labels, index, this.data.datasets[0].labels[index])
|
||||
},
|
||||
});
|
||||
|
||||
slice.pivot();
|
||||
}, this);
|
||||
},
|
||||
update: function(animationDuration) {
|
||||
|
||||
this.updateScaleRange();
|
||||
this.scale.calculateRange();
|
||||
this.scale.generateTicks();
|
||||
this.scale.buildYLabels();
|
||||
|
||||
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
|
||||
|
||||
var circumference = 1 / this.data.datasets[0].data.length * 2;
|
||||
|
||||
// Map new data to data points
|
||||
helpers.each(this.data.datasets[0].metaData, function(slice, index) {
|
||||
|
||||
var value = this.data.datasets[0].data[index];
|
||||
|
||||
var startAngle = (-0.5 * Math.PI) + (Math.PI * circumference) * index;
|
||||
var endAngle = startAngle + (circumference * Math.PI);
|
||||
|
||||
helpers.extend(slice, {
|
||||
_index: index,
|
||||
_model: {
|
||||
x: this.chart.width / 2,
|
||||
y: this.chart.height / 2,
|
||||
innerRadius: 0,
|
||||
outerRadius: this.scale.getDistanceFromCenterForValue(value),
|
||||
startAngle: startAngle,
|
||||
endAngle: endAngle,
|
||||
|
||||
backgroundColor: slice.custom && slice.custom.backgroundColor ? slice.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[0].backgroundColor, index, this.options.elements.arc.backgroundColor),
|
||||
hoverBackgroundColor: slice.custom && slice.custom.hoverBackgroundColor ? slice.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[0].hoverBackgroundColor, index, this.options.elements.arc.hoverBackgroundColor),
|
||||
borderWidth: slice.custom && slice.custom.borderWidth ? slice.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[0].borderWidth, index, this.options.elements.arc.borderWidth),
|
||||
borderColor: slice.custom && slice.custom.borderColor ? slice.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[0].borderColor, index, this.options.elements.arc.borderColor),
|
||||
|
||||
label: helpers.getValueAtIndexOrDefault(this.data.datasets[0].labels, index, this.data.datasets[0].labels[index])
|
||||
},
|
||||
});
|
||||
slice.pivot();
|
||||
|
||||
console.log(slice);
|
||||
|
||||
}, this);
|
||||
|
||||
this.render(animationDuration);
|
||||
},
|
||||
draw: function(ease) {
|
||||
var easingDecimal = ease || 1;
|
||||
|
||||
this.clear();
|
||||
|
||||
helpers.each(this.data.datasets[0].metaData, function(slice, index) {
|
||||
slice.transition(easingDecimal).draw();
|
||||
}, this);
|
||||
|
||||
this.scale.draw();
|
||||
|
||||
this.tooltip.transition(easingDecimal).draw();
|
||||
},
|
||||
events: function(e) {
|
||||
|
||||
// If exiting chart
|
||||
if (e.type == 'mouseout') {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.lastActive = this.lastActive || [];
|
||||
|
||||
// Find Active Elements
|
||||
this.active = function() {
|
||||
switch (this.options.hover.mode) {
|
||||
case 'single':
|
||||
return this.getSliceAtEvent(e);
|
||||
case 'label':
|
||||
return this.getSlicesAtEvent(e);
|
||||
case 'dataset':
|
||||
return this.getDatasetAtEvent(e);
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
}.call(this);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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':
|
||||
dataset = this.data.datasets[this.lastActive[0]._datasetIndex];
|
||||
index = this.lastActive[0]._index;
|
||||
|
||||
this.lastActive[0]._model.backgroundColor = this.lastActive[0].custom && this.lastActive[0].custom.backgroundColor ? this.lastActive[0].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, this.options.elements.arc.backgroundColor);
|
||||
this.lastActive[0]._model.borderColor = this.lastActive[0].custom && this.lastActive[0].custom.borderColor ? this.lastActive[0].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, this.options.elements.arc.borderColor);
|
||||
this.lastActive[0]._model.borderWidth = this.lastActive[0].custom && this.lastActive[0].custom.borderWidth ? this.lastActive[0].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.options.elements.arc.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.lastActive.length; i++) {
|
||||
dataset = this.data.datasets[this.lastActive[i]._datasetIndex];
|
||||
index = this.lastActive[i]._index;
|
||||
|
||||
this.lastActive[i]._model.backgroundColor = this.lastActive[i].custom && this.lastActive[i].custom.backgroundColor ? this.lastActive[i].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, this.options.elements.arc.backgroundColor);
|
||||
this.lastActive[i]._model.borderColor = this.lastActive[i].custom && this.lastActive[i].custom.borderColor ? this.lastActive[i].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, this.options.elements.arc.borderColor);
|
||||
this.lastActive[i]._model.borderWidth = this.lastActive[i].custom && this.lastActive[i].custom.borderWidth ? this.lastActive[i].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, this.options.elements.arc.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
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':
|
||||
dataset = this.data.datasets[this.active[0]._datasetIndex];
|
||||
index = this.active[0]._index;
|
||||
|
||||
this.active[0]._model.radius = this.active[0].custom && this.active[0].custom.hoverRadius ? this.active[0].custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.active[0]._model.radius + 1);
|
||||
this.active[0]._model.backgroundColor = this.active[0].custom && this.active[0].custom.hoverBackgroundColor ? this.active[0].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[0]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderColor = this.active[0].custom && this.active[0].custom.hoverBorderColor ? this.active[0].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[0]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderWidth = this.active[0].custom && this.active[0].custom.hoverBorderWidth ? this.active[0].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[0]._model.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.active.length; i++) {
|
||||
dataset = this.data.datasets[this.active[i]._datasetIndex];
|
||||
index = this.active[i]._index;
|
||||
|
||||
this.active[i]._model.radius = this.active[i].custom && this.active[i].custom.hoverRadius ? this.active[i].custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.active[i]._model.radius + 1);
|
||||
this.active[i]._model.backgroundColor = this.active[i].custom && this.active[i].custom.hoverBackgroundColor ? this.active[i].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[i]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderColor = this.active[i].custom && this.active[i].custom.hoverBorderColor ? this.active[i].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[i]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderWidth = this.active[i].custom && this.active[i].custom.hoverBorderWidth ? this.active[i].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[i]._model.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
break;
|
||||
default:
|
||||
// Don't change anything
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Built in Tooltips
|
||||
if (this.options.tooltips.enabled) {
|
||||
|
||||
// The usual updates
|
||||
this.tooltip.initialize();
|
||||
|
||||
// Active
|
||||
if (this.active.length) {
|
||||
this.tooltip._model.opacity = 1;
|
||||
|
||||
helpers.extend(this.tooltip, {
|
||||
_active: this.active,
|
||||
});
|
||||
|
||||
this.tooltip.update();
|
||||
} else {
|
||||
// Inactive
|
||||
this.tooltip._model.opacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// If entering, leaving, or changing elements, animate the change via pivot
|
||||
if ((!this.lastActive.length && this.active.length) ||
|
||||
(this.lastActive.length && !this.active.length) ||
|
||||
(this.lastActive.length && this.active.length && changed)) {
|
||||
|
||||
this.stop();
|
||||
this.render(this.options.hover.animationDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// Remember Last Active
|
||||
this.lastActive = this.active;
|
||||
return this;
|
||||
},
|
||||
getSliceAtEvent: function(e) {
|
||||
var elements = [];
|
||||
|
||||
var location = helpers.getRelativePosition(e);
|
||||
|
||||
this.eachElement(function(slice, index) {
|
||||
if (slice.inRange(location.x, location.y)) {
|
||||
elements.push(slice);
|
||||
}
|
||||
}, this);
|
||||
return elements;
|
||||
},
|
||||
/*getSlicesAtEvent: function(e) {
|
||||
var elements = [];
|
||||
|
||||
var location = helpers.getRelativePosition(e);
|
||||
|
||||
this.eachElement(function(slice, index) {
|
||||
if (slice.inGroupRange(location.x, location.y)) {
|
||||
elements.push(slice);
|
||||
}
|
||||
}, this);
|
||||
return elements;
|
||||
},*/
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,443 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
|
||||
|
||||
Chart.Type.extend({
|
||||
name: "Radar",
|
||||
defaults: {
|
||||
|
||||
scale: {
|
||||
type: "radialLinear",
|
||||
},
|
||||
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0, // no bezier in radar
|
||||
}
|
||||
},
|
||||
|
||||
//String - A legend template
|
||||
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
|
||||
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
|
||||
// Events
|
||||
helpers.bindEvents(this, this.options.events, this.events);
|
||||
|
||||
// Create a new line and its points for each dataset and piece of data
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
|
||||
dataset.metaDataset = new Chart.Line({
|
||||
_chart: this.chart,
|
||||
_datasetIndex: datasetIndex,
|
||||
_points: dataset.metaData,
|
||||
_loop: true
|
||||
});
|
||||
|
||||
dataset.metaData = [];
|
||||
|
||||
helpers.each(dataset.data, function(dataPoint, index) {
|
||||
dataset.metaData.push(new Chart.Point({
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
_chart: this.chart,
|
||||
_model: {
|
||||
x: 0, //xScale.getPixelForValue(null, index, true),
|
||||
y: 0, //this.chartArea.bottom,
|
||||
},
|
||||
}));
|
||||
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
// Build the scale.
|
||||
this.buildScale();
|
||||
|
||||
// Create tooltip instance exclusively for this chart with some defaults.
|
||||
this.tooltip = new Chart.Tooltip({
|
||||
_chart: this.chart,
|
||||
_data: this.data,
|
||||
_options: this.options,
|
||||
}, this);
|
||||
|
||||
// Need to fit scales before we reset elements.
|
||||
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
|
||||
|
||||
// Reset so that we animation from the baseline
|
||||
this.resetElements();
|
||||
|
||||
// Update that shiz
|
||||
this.update();
|
||||
},
|
||||
nextPoint: function(collection, index) {
|
||||
return collection[index + 1] || collection[0];
|
||||
},
|
||||
previousPoint: function(collection, index) {
|
||||
return collection[index - 1] || collection[collection.length - 1];
|
||||
},
|
||||
resetElements: function() {
|
||||
|
||||
// Update the points
|
||||
this.eachElement(function(point, index, dataset, datasetIndex) {
|
||||
helpers.extend(point, {
|
||||
// Utility
|
||||
_chart: this.chart,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
_scale: this.scale,
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
x: this.scale.xCenter,
|
||||
y: this.scale.yCenter,
|
||||
|
||||
// Appearance
|
||||
tension: point.custom && point.custom.tension ? point.custom.tension : this.options.elements.line.tension,
|
||||
radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointRadius, index, this.options.elements.point.radius),
|
||||
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBackgroundColor, index, this.options.elements.point.backgroundColor),
|
||||
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderColor, index, this.options.elements.point.borderColor),
|
||||
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderWidth, index, this.options.elements.point.borderWidth),
|
||||
skip: this.data.datasets[datasetIndex].data[index] === null,
|
||||
|
||||
// Tooltip
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].hitRadius, index, this.options.elements.point.hitRadius),
|
||||
},
|
||||
});
|
||||
}, this);
|
||||
|
||||
// Update control points for the bezier curve
|
||||
this.eachElement(function(point, index, dataset, datasetIndex) {
|
||||
var controlPoints = helpers.splineCurve(
|
||||
this.previousPoint(dataset, index)._model,
|
||||
point._model,
|
||||
this.nextPoint(dataset, index)._model,
|
||||
point._model.tension
|
||||
);
|
||||
|
||||
point._model.controlPointPreviousX = this.scale.xCenter;
|
||||
point._model.controlPointPreviousY = this.scale.yCenter;
|
||||
point._model.controlPointNextX = this.scale.xCenter;
|
||||
point._model.controlPointNextY = this.scale.yCenter;
|
||||
|
||||
// Now pivot the point for animation
|
||||
point.pivot();
|
||||
}, this);
|
||||
},
|
||||
update: function(animationDuration) {
|
||||
this.scale.setScaleSize();
|
||||
this.scale.calculateRange();
|
||||
this.scale.generateTicks();
|
||||
this.scale.buildYLabels();
|
||||
|
||||
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
|
||||
|
||||
// Update the lines
|
||||
this.eachDataset(function(dataset, datasetIndex) {
|
||||
var scaleBase;
|
||||
|
||||
if (this.scale.min < 0 && this.scale.max < 0) {
|
||||
scaleBase = this.scale.getPointPositionForValue(0, this.scale.max);
|
||||
} else if (this.scale.min > 0 && this.scale.max > 0) {
|
||||
scaleBase = this.scale.getPointPositionForValue(0, this.scale.min);
|
||||
} else {
|
||||
scaleBase = this.scale.getPointPositionForValue(0, 0);
|
||||
}
|
||||
|
||||
helpers.extend(dataset.metaDataset, {
|
||||
// Utility
|
||||
_datasetIndex: datasetIndex,
|
||||
|
||||
// Data
|
||||
_children: dataset.metaData,
|
||||
|
||||
// Model
|
||||
_model: {
|
||||
// Appearance
|
||||
tension: dataset.tension || this.options.elements.line.tension,
|
||||
backgroundColor: dataset.backgroundColor || this.options.elements.line.backgroundColor,
|
||||
borderWidth: dataset.borderWidth || this.options.elements.line.borderWidth,
|
||||
borderColor: dataset.borderColor || this.options.elements.line.borderColor,
|
||||
fill: dataset.fill !== undefined ? dataset.fill : this.options.elements.line.fill, // use the value from the dataset if it was provided. else fall back to the default
|
||||
skipNull: dataset.skipNull !== undefined ? dataset.skipNull : this.options.elements.line.skipNull,
|
||||
drawNull: dataset.drawNull !== undefined ? dataset.drawNull : this.options.elements.line.drawNull,
|
||||
|
||||
// Scale
|
||||
scaleTop: this.scale.top,
|
||||
scaleBottom: this.scale.bottom,
|
||||
scaleZero: scaleBase,
|
||||
},
|
||||
});
|
||||
|
||||
dataset.metaDataset.pivot();
|
||||
});
|
||||
|
||||
// Update the points
|
||||
this.eachElement(function(point, index, dataset, datasetIndex) {
|
||||
var pointPosition = this.scale.getPointPositionForValue(index, this.data.datasets[datasetIndex].data[index]);
|
||||
|
||||
helpers.extend(point, {
|
||||
// Utility
|
||||
_chart: this.chart,
|
||||
_datasetIndex: datasetIndex,
|
||||
_index: index,
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
x: pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
|
||||
y: pointPosition.y,
|
||||
|
||||
// Appearance
|
||||
tension: point.custom && point.custom.tension ? point.custom.tension : this.options.elements.line.tension,
|
||||
radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointRadius, index, this.options.elements.point.radius),
|
||||
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBackgroundColor, index, this.options.elements.point.backgroundColor),
|
||||
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderColor, index, this.options.elements.point.borderColor),
|
||||
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderWidth, index, this.options.elements.point.borderWidth),
|
||||
skip: this.data.datasets[datasetIndex].data[index] === null,
|
||||
|
||||
// Tooltip
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].hitRadius, index, this.options.elements.point.hitRadius),
|
||||
},
|
||||
});
|
||||
}, this);
|
||||
|
||||
|
||||
// Update control points for the bezier curve
|
||||
this.eachElement(function(point, index, dataset, datasetIndex) {
|
||||
var controlPoints = helpers.splineCurve(
|
||||
this.previousPoint(dataset, index)._model,
|
||||
point._model,
|
||||
this.nextPoint(dataset, index)._model,
|
||||
point._model.tension
|
||||
);
|
||||
|
||||
point._model.controlPointPreviousX = controlPoints.previous.x;
|
||||
point._model.controlPointNextX = controlPoints.next.x;
|
||||
|
||||
// Prevent the bezier going outside of the bounds of the graph
|
||||
|
||||
// Cap puter bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.next.y > this.chartArea.bottom) {
|
||||
point._model.controlPointNextY = this.chartArea.bottom;
|
||||
} else if (controlPoints.next.y < this.chartArea.top) {
|
||||
point._model.controlPointNextY = this.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointNextY = controlPoints.next.y;
|
||||
}
|
||||
|
||||
// Cap inner bezier handles to the upper/lower scale bounds
|
||||
if (controlPoints.previous.y > this.chartArea.bottom) {
|
||||
point._model.controlPointPreviousY = this.chartArea.bottom;
|
||||
} else if (controlPoints.previous.y < this.chartArea.top) {
|
||||
point._model.controlPointPreviousY = this.chartArea.top;
|
||||
} else {
|
||||
point._model.controlPointPreviousY = controlPoints.previous.y;
|
||||
}
|
||||
|
||||
// Now pivot the point for animation
|
||||
point.pivot();
|
||||
}, this);
|
||||
|
||||
this.render(animationDuration);
|
||||
},
|
||||
buildScale: function() {
|
||||
var self = this;
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor(this.options.scale.type);
|
||||
this.scale = new ScaleConstructor({
|
||||
options: this.options.scale,
|
||||
height: this.chart.height,
|
||||
width: this.chart.width,
|
||||
xCenter: this.chart.width / 2,
|
||||
yCenter: this.chart.height / 2,
|
||||
ctx: this.chart.ctx,
|
||||
labels: this.data.labels,
|
||||
valuesCount: this.data.datasets[0].data.length,
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
this.scale.setScaleSize();
|
||||
this.scale.calculateRange();
|
||||
this.scale.generateTicks();
|
||||
this.scale.buildYLabels();
|
||||
},
|
||||
draw: function(ease) {
|
||||
var easingDecimal = ease || 1;
|
||||
this.clear();
|
||||
|
||||
// Draw all the scales
|
||||
this.scale.draw(this.chartArea);
|
||||
|
||||
// reverse for-loop for proper stacking
|
||||
for (var i = this.data.datasets.length - 1; i >= 0; i--) {
|
||||
|
||||
var dataset = this.data.datasets[i];
|
||||
|
||||
// Transition Point Locations
|
||||
helpers.each(dataset.metaData, function(point, index) {
|
||||
point.transition(easingDecimal);
|
||||
}, this);
|
||||
|
||||
// Transition and Draw the line
|
||||
dataset.metaDataset.transition(easingDecimal).draw();
|
||||
|
||||
// Draw the points
|
||||
helpers.each(dataset.metaData, function(point) {
|
||||
point.draw();
|
||||
});
|
||||
}
|
||||
|
||||
// Finally draw the tooltip
|
||||
this.tooltip.transition(easingDecimal).draw();
|
||||
},
|
||||
events: function(e) {
|
||||
|
||||
this.lastActive = this.lastActive || [];
|
||||
|
||||
// Find Active Elements
|
||||
// If exiting chart
|
||||
if (e.type == 'mouseout') {
|
||||
this.active = [];
|
||||
} else {
|
||||
this.active = function() {
|
||||
switch (this.options.hover.mode) {
|
||||
case 'single':
|
||||
return this.getElementAtEvent(e);
|
||||
case 'label':
|
||||
return this.getElementsAtEvent(e);
|
||||
case 'dataset':
|
||||
return this.getDatasetAtEvent(e);
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
}.call(this);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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':
|
||||
dataset = this.data.datasets[this.lastActive[0]._datasetIndex];
|
||||
index = this.lastActive[0]._index;
|
||||
|
||||
this.lastActive[0]._model.radius = this.lastActive[0].custom && this.lastActive[0].custom.radius ? this.lastActive[0].custom.pointRadius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, this.options.elements.point.radius);
|
||||
this.lastActive[0]._model.backgroundColor = this.lastActive[0].custom && this.lastActive[0].custom.backgroundColor ? this.lastActive[0].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, this.options.elements.point.backgroundColor);
|
||||
this.lastActive[0]._model.borderColor = this.lastActive[0].custom && this.lastActive[0].custom.borderColor ? this.lastActive[0].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, this.options.elements.point.borderColor);
|
||||
this.lastActive[0]._model.borderWidth = this.lastActive[0].custom && this.lastActive[0].custom.borderWidth ? this.lastActive[0].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.options.elements.point.borderWidth);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.lastActive.length; i++) {
|
||||
dataset = this.data.datasets[this.lastActive[i]._datasetIndex];
|
||||
index = this.lastActive[i]._index;
|
||||
|
||||
this.lastActive[i]._model.radius = this.lastActive[i].custom && this.lastActive[i].custom.radius ? this.lastActive[i].custom.pointRadius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, this.options.elements.point.radius);
|
||||
this.lastActive[i]._model.backgroundColor = this.lastActive[i].custom && this.lastActive[i].custom.backgroundColor ? this.lastActive[i].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, this.options.elements.point.backgroundColor);
|
||||
this.lastActive[i]._model.borderColor = this.lastActive[i].custom && this.lastActive[i].custom.borderColor ? this.lastActive[i].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, this.options.elements.point.borderColor);
|
||||
this.lastActive[i]._model.borderWidth = this.lastActive[i].custom && this.lastActive[i].custom.borderWidth ? this.lastActive[i].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.options.elements.point.borderWidth);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
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':
|
||||
dataset = this.data.datasets[this.active[0]._datasetIndex];
|
||||
index = this.active[0]._index;
|
||||
|
||||
this.active[0]._model.radius = this.active[0].custom && this.active[0].custom.hoverRadius ? this.active[0].custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.active[0]._model.radius + 2);
|
||||
this.active[0]._model.backgroundColor = this.active[0].custom && this.active[0].custom.hoverBackgroundColor ? this.active[0].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[0]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderColor = this.active[0].custom && this.active[0].custom.hoverBorderColor ? this.active[0].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[0]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[0]._model.borderWidth = this.active[0].custom && this.active[0].custom.hoverBorderWidth ? this.active[0].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[0]._model.borderWidth + 2);
|
||||
break;
|
||||
case 'label':
|
||||
for (var i = 0; i < this.active.length; i++) {
|
||||
dataset = this.data.datasets[this.active[i]._datasetIndex];
|
||||
index = this.active[i]._index;
|
||||
|
||||
this.active[i]._model.radius = this.active[i].custom && this.active[i].custom.hoverRadius ? this.active[i].custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.active[i]._model.radius + 2);
|
||||
this.active[i]._model.backgroundColor = this.active[i].custom && this.active[i].custom.hoverBackgroundColor ? this.active[i].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[i]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderColor = this.active[i].custom && this.active[i].custom.hoverBorderColor ? this.active[i].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[i]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
this.active[i]._model.borderWidth = this.active[i].custom && this.active[i].custom.hoverBorderWidth ? this.active[i].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[i]._model.borderWidth + 2);
|
||||
}
|
||||
break;
|
||||
case 'dataset':
|
||||
break;
|
||||
default:
|
||||
// Don't change anything
|
||||
}
|
||||
}
|
||||
|
||||
// Built in Tooltips
|
||||
if (this.options.tooltips.enabled) {
|
||||
|
||||
// The usual updates
|
||||
this.tooltip.initialize();
|
||||
|
||||
// Active
|
||||
if (this.active.length) {
|
||||
this.tooltip._model.opacity = 1;
|
||||
|
||||
helpers.extend(this.tooltip, {
|
||||
_active: this.active,
|
||||
});
|
||||
|
||||
this.tooltip.update();
|
||||
} else {
|
||||
// Inactive
|
||||
this.tooltip._model.opacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// If entering, leaving, or changing elements, animate the change via pivot
|
||||
if ((!this.lastActive.length && this.active.length) ||
|
||||
(this.lastActive.length && !this.active.length) ||
|
||||
(this.lastActive.length && this.active.length && changed)) {
|
||||
|
||||
this.stop();
|
||||
this.render(this.options.hover.animationDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// Remember Last Active
|
||||
this.lastActive = this.active;
|
||||
return this;
|
||||
},
|
||||
});
|
||||
}).call(this);
|
||||
@@ -0,0 +1,41 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
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",
|
||||
}],
|
||||
},
|
||||
|
||||
//String - A legend template
|
||||
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].borderColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>",
|
||||
|
||||
tooltips: {
|
||||
template: "(<%= value.x %>, <%= value.y %>)",
|
||||
multiTemplate: "<%if (datasetLabel){%><%=datasetLabel%>: <%}%>(<%= value.x %>, <%= value.y %>)",
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
Chart.types.Line.extend({
|
||||
name: "Scatter",
|
||||
defaults: defaultConfig,
|
||||
});
|
||||
}).call(this);
|
||||
@@ -0,0 +1,127 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* 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.animation = {
|
||||
duration: 1000,
|
||||
easing: "easeOutQuart",
|
||||
onProgress: function() {},
|
||||
onComplete: function() {},
|
||||
};
|
||||
|
||||
Chart.Animation = Chart.Element.extend({
|
||||
currentStep: null, // the current animation step
|
||||
numSteps: 60, // default number of steps
|
||||
easing: "", // the easing to use for this animation
|
||||
render: null, // render function used by the animation service
|
||||
|
||||
onAnimationProgress: null, // user specified callback to fire on each step of the animation
|
||||
onAnimationComplete: null, // user specified callback to fire when the animation finishes
|
||||
});
|
||||
|
||||
Chart.animationService = {
|
||||
frameDuration: 17,
|
||||
animations: [],
|
||||
dropFrames: 0,
|
||||
addAnimation: function(chartInstance, animationObject, duration) {
|
||||
|
||||
if (!duration) {
|
||||
chartInstance.animating = true;
|
||||
}
|
||||
|
||||
for (var index = 0; index < this.animations.length; ++index) {
|
||||
if (this.animations[index].chartInstance === chartInstance) {
|
||||
// replacing an in progress animation
|
||||
this.animations[index].animationObject = animationObject;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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 -= framesToDrop;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.animations.length; i++) {
|
||||
|
||||
if (this.animations[i].animationObject.currentStep === null) {
|
||||
this.animations[i].animationObject.currentStep = 0;
|
||||
}
|
||||
|
||||
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.currentStep == this.animations[i].animationObject.numSteps) {
|
||||
// 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 delay = endTime - startTime - this.frameDuration;
|
||||
var frameDelay = delay / this.frameDuration;
|
||||
|
||||
if (frameDelay > 1) {
|
||||
this.dropFrames += frameDelay;
|
||||
}
|
||||
|
||||
// Do we have more stuff to animate?
|
||||
if (this.animations.length > 0) {
|
||||
helpers.requestAnimFrame.call(window, this.digestWrapper);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
Arquivo executável
+1252
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -0,0 +1,269 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
// The scale service is used to resize charts along with all of their axes. We make this as
|
||||
// a service where scales are registered with their respective charts so that changing the
|
||||
// scales does not require
|
||||
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] = defaults;
|
||||
},
|
||||
getScaleConstructor: function(type) {
|
||||
return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
|
||||
},
|
||||
getScaleDefaults: function(type) {
|
||||
return this.defaults.hasOwnProperty(type) ? this.defaults[type] : {};
|
||||
},
|
||||
// The interesting function
|
||||
fitScalesForChart: function(chartInstance, width, height) {
|
||||
var xPadding = width > 30 ? 5 : 2;
|
||||
var yPadding = height > 30 ? 5 : 2;
|
||||
|
||||
if (chartInstance) {
|
||||
var leftScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "left";
|
||||
});
|
||||
var rightScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "right";
|
||||
});
|
||||
var topScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "top";
|
||||
});
|
||||
var bottomScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "bottom";
|
||||
});
|
||||
|
||||
// Essentially we now have any number of scales 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
|
||||
// |------------------------------------------------------|
|
||||
// | | T1 | |
|
||||
// |----|-----|-------------------------------------|-----|
|
||||
// | | | | |
|
||||
// | L1 | L2 | Chart area | R1 |
|
||||
// | | | | |
|
||||
// | | | | |
|
||||
// |----|-----|-------------------------------------|-----|
|
||||
// | | B1 | |
|
||||
// | | | |
|
||||
// |------------------------------------------------------|
|
||||
|
||||
// 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 scale the maximum size it can be. The scale 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
|
||||
|
||||
// Step 1
|
||||
var chartWidth = width / 2; // min 50%
|
||||
var chartHeight = height / 2; // min 50%
|
||||
|
||||
chartWidth -= (2 * xPadding);
|
||||
chartHeight -= (2 * yPadding);
|
||||
|
||||
|
||||
// Step 2
|
||||
var verticalScaleWidth = (width - chartWidth) / (leftScales.length + rightScales.length);
|
||||
|
||||
// Step 3
|
||||
var horizontalScaleHeight = (height - chartHeight) / (topScales.length + bottomScales.length);
|
||||
|
||||
// Step 4;
|
||||
var minimumScaleSizes = [];
|
||||
|
||||
var verticalScaleMinSizeFunction = function(scaleInstance) {
|
||||
var minSize = scaleInstance.fit(verticalScaleWidth, chartHeight);
|
||||
minimumScaleSizes.push({
|
||||
horizontal: false,
|
||||
minSize: minSize,
|
||||
scale: scaleInstance,
|
||||
});
|
||||
};
|
||||
|
||||
var horizontalScaleMinSizeFunction = function(scaleInstance) {
|
||||
var minSize = scaleInstance.fit(chartWidth, horizontalScaleHeight);
|
||||
minimumScaleSizes.push({
|
||||
horizontal: true,
|
||||
minSize: minSize,
|
||||
scale: scaleInstance,
|
||||
});
|
||||
};
|
||||
|
||||
// vertical scales
|
||||
helpers.each(leftScales, verticalScaleMinSizeFunction);
|
||||
helpers.each(rightScales, verticalScaleMinSizeFunction);
|
||||
|
||||
// horizontal scales
|
||||
helpers.each(topScales, horizontalScaleMinSizeFunction);
|
||||
helpers.each(bottomScales, horizontalScaleMinSizeFunction);
|
||||
|
||||
// Step 5
|
||||
var maxChartHeight = height - (2 * yPadding);
|
||||
var maxChartWidth = width - (2 * xPadding);
|
||||
|
||||
helpers.each(minimumScaleSizes, function(wrapper) {
|
||||
if (wrapper.horizontal) {
|
||||
maxChartHeight -= wrapper.minSize.height;
|
||||
} else {
|
||||
maxChartWidth -= wrapper.minSize.width;
|
||||
}
|
||||
});
|
||||
|
||||
// At this point, maxChartHeight and maxChartWidth are the size the chart area could
|
||||
// be if the axes are drawn at their minimum sizes.
|
||||
|
||||
// Step 6
|
||||
var verticalScaleFitFunction = function(scaleInstance) {
|
||||
var wrapper = helpers.findNextWhere(minimumScaleSizes, function(wrapper) {
|
||||
return wrapper.scale === scaleInstance;
|
||||
});
|
||||
|
||||
if (wrapper) {
|
||||
scaleInstance.fit(wrapper.minSize.width, maxChartHeight);
|
||||
}
|
||||
};
|
||||
|
||||
var horizontalScaleFitFunction = function(scaleInstance) {
|
||||
var wrapper = helpers.findNextWhere(minimumScaleSizes, function(wrapper) {
|
||||
return wrapper.scale === scaleInstance;
|
||||
});
|
||||
|
||||
var scaleMargin = {
|
||||
left: totalLeftWidth,
|
||||
right: totalRightWidth,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
};
|
||||
|
||||
if (wrapper) {
|
||||
scaleInstance.fit(maxChartWidth, wrapper.minSize.height, scaleMargin);
|
||||
}
|
||||
};
|
||||
|
||||
var totalLeftWidth = xPadding;
|
||||
var totalRightWidth = xPadding;
|
||||
var totalTopHeight = yPadding;
|
||||
var totalBottomHeight = yPadding;
|
||||
|
||||
helpers.each(leftScales, verticalScaleFitFunction);
|
||||
helpers.each(rightScales, verticalScaleFitFunction);
|
||||
|
||||
// Figure out how much margin is on the left and right of the horizontal axes
|
||||
helpers.each(leftScales, function(scaleInstance) {
|
||||
totalLeftWidth += scaleInstance.width;
|
||||
});
|
||||
|
||||
helpers.each(rightScales, function(scaleInstance) {
|
||||
totalRightWidth += scaleInstance.width;
|
||||
});
|
||||
|
||||
helpers.each(topScales, horizontalScaleFitFunction);
|
||||
helpers.each(bottomScales, horizontalScaleFitFunction);
|
||||
|
||||
helpers.each(topScales, function(scaleInstance) {
|
||||
totalTopHeight += scaleInstance.height;
|
||||
});
|
||||
helpers.each(bottomScales, function(scaleInstance) {
|
||||
totalBottomHeight += scaleInstance.height;
|
||||
});
|
||||
|
||||
// Let the left scale know the final margin
|
||||
helpers.each(leftScales, function(scaleInstance) {
|
||||
var wrapper = helpers.findNextWhere(minimumScaleSizes, function(wrapper) {
|
||||
return wrapper.scale === scaleInstance;
|
||||
});
|
||||
|
||||
var scaleMargin = {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: totalTopHeight,
|
||||
bottom: totalBottomHeight
|
||||
};
|
||||
|
||||
if (wrapper) {
|
||||
scaleInstance.fit(wrapper.minSize.width, maxChartHeight, scaleMargin);
|
||||
}
|
||||
});
|
||||
|
||||
helpers.each(rightScales, function(scaleInstance) {
|
||||
var wrapper = helpers.findNextWhere(minimumScaleSizes, function(wrapper) {
|
||||
return wrapper.scale === scaleInstance;
|
||||
});
|
||||
|
||||
var scaleMargin = {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: totalTopHeight,
|
||||
bottom: totalBottomHeight
|
||||
};
|
||||
|
||||
if (wrapper) {
|
||||
scaleInstance.fit(wrapper.minSize.width, maxChartHeight, scaleMargin);
|
||||
}
|
||||
});
|
||||
|
||||
// Step 7
|
||||
// Position the scales
|
||||
var left = xPadding;
|
||||
var top = yPadding;
|
||||
var right = 0;
|
||||
var bottom = 0;
|
||||
|
||||
var verticalScalePlacer = function(scaleInstance) {
|
||||
scaleInstance.left = left;
|
||||
scaleInstance.right = left + scaleInstance.width;
|
||||
scaleInstance.top = totalTopHeight;
|
||||
scaleInstance.bottom = totalTopHeight + maxChartHeight;
|
||||
|
||||
// Move to next point
|
||||
left = scaleInstance.right;
|
||||
};
|
||||
|
||||
var horizontalScalePlacer = function(scaleInstance) {
|
||||
scaleInstance.left = totalLeftWidth;
|
||||
scaleInstance.right = totalLeftWidth + maxChartWidth;
|
||||
scaleInstance.top = top;
|
||||
scaleInstance.bottom = top + scaleInstance.height;
|
||||
|
||||
// Move to next point
|
||||
top = scaleInstance.bottom;
|
||||
};
|
||||
|
||||
helpers.each(leftScales, verticalScalePlacer);
|
||||
helpers.each(topScales, horizontalScalePlacer);
|
||||
|
||||
// Account for chart width and height
|
||||
left += maxChartWidth;
|
||||
top += maxChartHeight;
|
||||
|
||||
helpers.each(rightScales, verticalScalePlacer);
|
||||
helpers.each(bottomScales, horizontalScalePlacer);
|
||||
|
||||
// Step 8
|
||||
chartInstance.chartArea = {
|
||||
left: totalLeftWidth,
|
||||
top: totalTopHeight,
|
||||
right: totalLeftWidth + maxChartWidth,
|
||||
bottom: totalTopHeight + maxChartHeight,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}).call(this);
|
||||
@@ -0,0 +1,344 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* 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.tooltips = {
|
||||
enabled: true,
|
||||
custom: null,
|
||||
backgroundColor: "rgba(0,0,0,0.8)",
|
||||
fontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
fontSize: 10,
|
||||
fontStyle: "normal",
|
||||
fontColor: "#fff",
|
||||
titleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
titleFontSize: 12,
|
||||
titleFontStyle: "bold",
|
||||
titleFontColor: "#fff",
|
||||
yPadding: 6,
|
||||
xPadding: 6,
|
||||
caretSize: 8,
|
||||
cornerRadius: 6,
|
||||
xOffset: 10,
|
||||
template: [
|
||||
'<% if(label){ %>',
|
||||
'<%=label %>: ',
|
||||
'<% } %>',
|
||||
'<%=value %>',
|
||||
].join(''),
|
||||
multiTemplate: [
|
||||
'<%if (datasetLabel){ %>',
|
||||
'<%=datasetLabel %>: ',
|
||||
'<% } %>',
|
||||
'<%=value %>'
|
||||
].join(''),
|
||||
multiKeyBackground: '#fff',
|
||||
};
|
||||
|
||||
Chart.Tooltip = Chart.Element.extend({
|
||||
initialize: function() {
|
||||
var options = this._options;
|
||||
helpers.extend(this, {
|
||||
_model: {
|
||||
// Positioning
|
||||
xPadding: options.tooltips.xPadding,
|
||||
yPadding: options.tooltips.yPadding,
|
||||
xOffset: options.tooltips.xOffset,
|
||||
|
||||
// Labels
|
||||
textColor: options.tooltips.fontColor,
|
||||
_fontFamily: options.tooltips.fontFamily,
|
||||
_fontStyle: options.tooltips.fontStyle,
|
||||
fontSize: options.tooltips.fontSize,
|
||||
|
||||
// Title
|
||||
titleTextColor: options.tooltips.titleFontColor,
|
||||
_titleFontFamily: options.tooltips.titleFontFamily,
|
||||
_titleFontStyle: options.tooltips.titleFontStyle,
|
||||
titleFontSize: options.tooltips.titleFontSize,
|
||||
|
||||
// Appearance
|
||||
caretHeight: options.tooltips.caretSize,
|
||||
cornerRadius: options.tooltips.cornerRadius,
|
||||
backgroundColor: options.tooltips.backgroundColor,
|
||||
opacity: 0,
|
||||
legendColorBackground: options.tooltips.multiKeyBackground,
|
||||
},
|
||||
});
|
||||
},
|
||||
update: function() {
|
||||
|
||||
var ctx = this._chart.ctx;
|
||||
|
||||
switch (this._options.hover.mode) {
|
||||
case 'single':
|
||||
helpers.extend(this._model, {
|
||||
text: helpers.template(this._options.tooltips.template, {
|
||||
// These variables are available in the template function. Add others here
|
||||
element: this._active[0],
|
||||
value: this._data.datasets[this._active[0]._datasetIndex].data[this._active[0]._index],
|
||||
label: this._data.labels ? this._data.labels[this._active[0]._index] : '',
|
||||
}),
|
||||
});
|
||||
|
||||
var tooltipPosition = this._active[0].tooltipPosition();
|
||||
helpers.extend(this._model, {
|
||||
x: Math.round(tooltipPosition.x),
|
||||
y: Math.round(tooltipPosition.y),
|
||||
caretPadding: tooltipPosition.padding
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
case 'label':
|
||||
|
||||
// Tooltip Content
|
||||
|
||||
var dataArray,
|
||||
dataIndex;
|
||||
|
||||
var labels = [],
|
||||
colors = [];
|
||||
|
||||
for (var i = this._data.datasets.length - 1; i >= 0; i--) {
|
||||
dataArray = this._data.datasets[i].metaData;
|
||||
dataIndex = helpers.indexOf(dataArray, this._active[0]);
|
||||
if (dataIndex !== -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var medianPosition = (function(index) {
|
||||
// Get all the points at that particular index
|
||||
var elements = [],
|
||||
dataCollection,
|
||||
xPositions = [],
|
||||
yPositions = [],
|
||||
xMax,
|
||||
yMax,
|
||||
xMin,
|
||||
yMin;
|
||||
helpers.each(this._data.datasets, function(dataset) {
|
||||
dataCollection = dataset.metaData;
|
||||
if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()) {
|
||||
elements.push(dataCollection[dataIndex]);
|
||||
}
|
||||
}, this);
|
||||
|
||||
// Reverse labels if stacked
|
||||
helpers.each(this._options.stacked ? elements.reverse() : elements, function(element) {
|
||||
xPositions.push(element._view.x);
|
||||
yPositions.push(element._view.y);
|
||||
|
||||
//Include any colour information about the element
|
||||
labels.push(helpers.template(this._options.tooltips.multiTemplate, {
|
||||
// These variables are available in the template function. Add others here
|
||||
element: element,
|
||||
datasetLabel: this._data.datasets[element._datasetIndex].label,
|
||||
value: this._data.datasets[element._datasetIndex].data[element._index],
|
||||
}));
|
||||
colors.push({
|
||||
fill: element._view.backgroundColor,
|
||||
stroke: element._view.borderColor
|
||||
});
|
||||
|
||||
}, this);
|
||||
|
||||
yMin = helpers.min(yPositions);
|
||||
yMax = helpers.max(yPositions);
|
||||
|
||||
xMin = helpers.min(xPositions);
|
||||
xMax = helpers.max(xPositions);
|
||||
|
||||
return {
|
||||
x: (xMin > this._chart.width / 2) ? xMin : xMax,
|
||||
y: (yMin + yMax) / 2,
|
||||
};
|
||||
}).call(this, dataIndex);
|
||||
|
||||
// Apply for now
|
||||
helpers.extend(this._model, {
|
||||
x: medianPosition.x,
|
||||
y: medianPosition.y,
|
||||
labels: labels,
|
||||
title: this._data.labels && this._data.labels.length ? this._data.labels[this._active[0]._index] : '',
|
||||
legendColors: colors,
|
||||
legendBackgroundColor: this._options.tooltips.multiKeyBackground,
|
||||
});
|
||||
|
||||
|
||||
// Calculate Appearance Tweaks
|
||||
|
||||
this._model.height = (labels.length * this._model.fontSize) + ((labels.length - 1) * (this._model.fontSize / 2)) + (this._model.yPadding * 2) + this._model.titleFontSize * 1.5;
|
||||
|
||||
var titleWidth = ctx.measureText(this.title).width,
|
||||
//Label has a legend square as well so account for this.
|
||||
labelWidth = helpers.longestText(ctx, this.font, labels) + this._model.fontSize + 3,
|
||||
longestTextWidth = helpers.max([labelWidth, titleWidth]);
|
||||
|
||||
this._model.width = longestTextWidth + (this._model.xPadding * 2);
|
||||
|
||||
|
||||
var halfHeight = this._model.height / 2;
|
||||
|
||||
//Check to ensure the height will fit on the canvas
|
||||
if (this._model.y - halfHeight < 0) {
|
||||
this._model.y = halfHeight;
|
||||
} else if (this._model.y + halfHeight > this._chart.height) {
|
||||
this._model.y = this._chart.height - halfHeight;
|
||||
}
|
||||
|
||||
//Decide whether to align left or right based on position on canvas
|
||||
if (this._model.x > this._chart.width / 2) {
|
||||
this._model.x -= this._model.xOffset + this._model.width;
|
||||
} else {
|
||||
this._model.x += this._model.xOffset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
draw: function() {
|
||||
|
||||
var ctx = this._chart.ctx;
|
||||
var vm = this._view;
|
||||
|
||||
switch (this._options.hover.mode) {
|
||||
case 'single':
|
||||
|
||||
ctx.font = helpers.fontString(vm.fontSize, vm._fontStyle, vm._fontFamily);
|
||||
|
||||
vm.xAlign = "center";
|
||||
vm.yAlign = "above";
|
||||
|
||||
//Distance between the actual element.y position and the start of the tooltip caret
|
||||
var caretPadding = vm.caretPadding || 2;
|
||||
|
||||
var tooltipWidth = ctx.measureText(vm.text).width + 2 * vm.xPadding,
|
||||
tooltipRectHeight = vm.fontSize + 2 * vm.yPadding,
|
||||
tooltipHeight = tooltipRectHeight + vm.caretHeight + caretPadding;
|
||||
|
||||
if (vm.x + tooltipWidth / 2 > this._chart.width) {
|
||||
vm.xAlign = "left";
|
||||
} else if (vm.x - tooltipWidth / 2 < 0) {
|
||||
vm.xAlign = "right";
|
||||
}
|
||||
|
||||
if (vm.y - tooltipHeight < 0) {
|
||||
vm.yAlign = "below";
|
||||
}
|
||||
|
||||
var tooltipX = vm.x - tooltipWidth / 2,
|
||||
tooltipY = vm.y - tooltipHeight;
|
||||
|
||||
ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(vm.opacity).rgbString();
|
||||
|
||||
// Custom Tooltips
|
||||
if (this._custom) {
|
||||
this._custom(this._view);
|
||||
} else {
|
||||
switch (vm.yAlign) {
|
||||
case "above":
|
||||
//Draw a caret above the x/y
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vm.x, vm.y - caretPadding);
|
||||
ctx.lineTo(vm.x + vm.caretHeight, vm.y - (caretPadding + vm.caretHeight));
|
||||
ctx.lineTo(vm.x - vm.caretHeight, vm.y - (caretPadding + vm.caretHeight));
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
break;
|
||||
case "below":
|
||||
tooltipY = vm.y + caretPadding + vm.caretHeight;
|
||||
//Draw a caret below the x/y
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vm.x, vm.y + caretPadding);
|
||||
ctx.lineTo(vm.x + vm.caretHeight, vm.y + caretPadding + vm.caretHeight);
|
||||
ctx.lineTo(vm.x - vm.caretHeight, vm.y + caretPadding + vm.caretHeight);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (vm.xAlign) {
|
||||
case "left":
|
||||
tooltipX = vm.x - tooltipWidth + (vm.cornerRadius + vm.caretHeight);
|
||||
break;
|
||||
case "right":
|
||||
tooltipX = vm.x - (vm.cornerRadius + vm.caretHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
helpers.drawRoundedRectangle(ctx, tooltipX, tooltipY, tooltipWidth, tooltipRectHeight, vm.cornerRadius);
|
||||
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = helpers.color(vm.textColor).alpha(vm.opacity).rgbString();
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillText(vm.text, tooltipX + tooltipWidth / 2, tooltipY + tooltipRectHeight / 2);
|
||||
|
||||
}
|
||||
break;
|
||||
case 'label':
|
||||
|
||||
helpers.drawRoundedRectangle(ctx, vm.x, vm.y - vm.height / 2, vm.width, vm.height, vm.cornerRadius);
|
||||
ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(vm.opacity).rgbString();
|
||||
ctx.fill();
|
||||
ctx.closePath();
|
||||
|
||||
ctx.textAlign = "left";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = helpers.color(vm.titleTextColor).alpha(vm.opacity).rgbString();
|
||||
ctx.font = helpers.fontString(vm.fontSize, vm._titleFontStyle, vm._titleFontFamily);
|
||||
ctx.fillText(vm.title, vm.x + vm.xPadding, this.getLineHeight(0));
|
||||
|
||||
ctx.font = helpers.fontString(vm.fontSize, vm._fontStyle, vm._fontFamily);
|
||||
helpers.each(vm.labels, function(label, index) {
|
||||
ctx.fillStyle = helpers.color(vm.textColor).alpha(vm.opacity).rgbString();
|
||||
ctx.fillText(label, vm.x + vm.xPadding + vm.fontSize + 3, this.getLineHeight(index + 1));
|
||||
|
||||
//A bit gnarly, but clearing this rectangle breaks when using explorercanvas (clears whole canvas)
|
||||
//ctx.clearRect(vm.x + vm.xPadding, this.getLineHeight(index + 1) - vm.fontSize/2, vm.fontSize, vm.fontSize);
|
||||
//Instead we'll make a white filled block to put the legendColour palette over.
|
||||
|
||||
ctx.fillStyle = helpers.color(vm.legendColors[index].stroke).alpha(vm.opacity).rgbString();
|
||||
ctx.fillRect(vm.x + vm.xPadding - 1, this.getLineHeight(index + 1) - vm.fontSize / 2 - 1, vm.fontSize + 2, vm.fontSize + 2);
|
||||
|
||||
ctx.fillStyle = helpers.color(vm.legendColors[index].fill).alpha(vm.opacity).rgbString();
|
||||
ctx.fillRect(vm.x + vm.xPadding, this.getLineHeight(index + 1) - vm.fontSize / 2, vm.fontSize, vm.fontSize);
|
||||
|
||||
|
||||
}, this);
|
||||
break;
|
||||
}
|
||||
},
|
||||
getLineHeight: function(index) {
|
||||
var baseLineHeight = this._view.y - (this._view.height / 2) + this._view.yPadding,
|
||||
afterTitleIndex = index - 1;
|
||||
|
||||
//If the index is zero, we're getting the title
|
||||
if (index === 0) {
|
||||
return baseLineHeight + this._view.titleFontSize / 2;
|
||||
} else {
|
||||
return baseLineHeight + ((this._view.fontSize * 1.5 * afterTitleIndex) + this._view.fontSize / 2) + this._view.titleFontSize * 1.5;
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,93 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* 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.Arc = Chart.Element.extend({
|
||||
inGroupRange: 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;
|
||||
|
||||
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);
|
||||
//Ensure within the outside of the arc centre, but inside arc outer
|
||||
},
|
||||
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);
|
||||
@@ -0,0 +1,190 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* 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,
|
||||
fill: true, // do we fill in the area between the line and its base axis
|
||||
skipNull: true,
|
||||
drawNull: false,
|
||||
};
|
||||
|
||||
|
||||
Chart.Line = Chart.Element.extend({
|
||||
draw: function() {
|
||||
|
||||
var vm = this._view;
|
||||
var ctx = this._chart.ctx;
|
||||
var first = this._children[0];
|
||||
var last = this._children[this._children.length - 1];
|
||||
|
||||
// Draw the background first (so the border is always on top)
|
||||
helpers.each(this._children, function(point, index) {
|
||||
var previous = this.previousPoint(point, this._children, index);
|
||||
var next = this.nextPoint(point, this._children, index);
|
||||
|
||||
// First point only
|
||||
if (index === 0) {
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start Skip and drag along scale baseline
|
||||
if (point._view.skip && vm.skipNull && !this._loop) {
|
||||
ctx.lineTo(previous._view.x, point._view.y);
|
||||
ctx.moveTo(next._view.x, point._view.y);
|
||||
}
|
||||
// End Skip Stright line from the base line
|
||||
else if (previous._view.skip && vm.skipNull && !this._loop) {
|
||||
ctx.moveTo(point._view.x, previous._view.y);
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
}
|
||||
|
||||
if (previous._view.skip && vm.skipNull) {
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
}
|
||||
// Normal Bezier Curve
|
||||
else {
|
||||
if (vm.tension > 0) {
|
||||
ctx.bezierCurveTo(
|
||||
previous._view.controlPointNextX,
|
||||
previous._view.controlPointNextY,
|
||||
point._view.controlPointPreviousX,
|
||||
point._view.controlPointPreviousY,
|
||||
point._view.x,
|
||||
point._view.y
|
||||
);
|
||||
} else {
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
// For radial scales, loop back around to the first point
|
||||
if (this._loop) {
|
||||
if (vm.tension > 0 && !first._view.skip) {
|
||||
|
||||
ctx.bezierCurveTo(
|
||||
last._view.controlPointNextX,
|
||||
last._view.controlPointNextY,
|
||||
first._view.controlPointPreviousX,
|
||||
first._view.controlPointPreviousY,
|
||||
first._view.x,
|
||||
first._view.y
|
||||
);
|
||||
} else {
|
||||
ctx.lineTo(first._view.x, first._view.y);
|
||||
}
|
||||
}
|
||||
|
||||
// If we had points and want to fill this line, do so.
|
||||
if (this._children.length > 0 && vm.fill) {
|
||||
//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.lineWidth = vm.borderWidth || Chart.defaults.global.defaultColor;
|
||||
ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor;
|
||||
ctx.beginPath();
|
||||
|
||||
helpers.each(this._children, function(point, index) {
|
||||
var previous = this.previousPoint(point, this._children, index);
|
||||
var next = this.nextPoint(point, this._children, index);
|
||||
|
||||
// First point only
|
||||
if (index === 0) {
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start Skip and drag along scale baseline
|
||||
if (point._view.skip && vm.skipNull && !this._loop) {
|
||||
ctx.moveTo(previous._view.x, point._view.y);
|
||||
ctx.moveTo(next._view.x, point._view.y);
|
||||
return;
|
||||
}
|
||||
// End Skip Stright line from the base line
|
||||
if (previous._view.skip && vm.skipNull && !this._loop) {
|
||||
ctx.moveTo(point._view.x, previous._view.y);
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
return;
|
||||
}
|
||||
|
||||
if (previous._view.skip && vm.skipNull) {
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
return;
|
||||
}
|
||||
// Normal Bezier Curve
|
||||
if (vm.tension > 0) {
|
||||
ctx.bezierCurveTo(
|
||||
previous._view.controlPointNextX,
|
||||
previous._view.controlPointNextY,
|
||||
point._view.controlPointPreviousX,
|
||||
point._view.controlPointPreviousY,
|
||||
point._view.x,
|
||||
point._view.y
|
||||
);
|
||||
} else {
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (this._loop && !first._view.skip) {
|
||||
if (vm.tension > 0) {
|
||||
|
||||
ctx.bezierCurveTo(
|
||||
last._view.controlPointNextX,
|
||||
last._view.controlPointNextY,
|
||||
first._view.controlPointPreviousX,
|
||||
first._view.controlPointPreviousY,
|
||||
first._view.x,
|
||||
first._view.y
|
||||
);
|
||||
} else {
|
||||
ctx.lineTo(first._view.x, first._view.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
},
|
||||
nextPoint: function(point, collection, index) {
|
||||
if (this.loop) {
|
||||
return collection[index + 1] || collection[0];
|
||||
}
|
||||
return collection[index + 1] || collection[collection.length - 1];
|
||||
},
|
||||
previousPoint: function(point, collection, index) {
|
||||
if (this.loop) {
|
||||
return collection[index - 1] || collection[collection.length - 1];
|
||||
}
|
||||
return collection[index - 1] || collection[0];
|
||||
},
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,84 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* 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.Point = Chart.Element.extend({
|
||||
inRange: function(mouseX, mouseY) {
|
||||
var vm = this._view;
|
||||
var hoverRange = vm.hitRadius + vm.radius;
|
||||
return ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(hoverRange, 2));
|
||||
},
|
||||
inGroupRange: 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);
|
||||
@@ -0,0 +1,95 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* 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.rectangle = {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 0,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
};
|
||||
|
||||
Chart.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;
|
||||
if (vm.y < vm.base) {
|
||||
return (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.y && mouseY <= vm.base);
|
||||
} else {
|
||||
return (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.base && mouseY <= vm.y);
|
||||
}
|
||||
},
|
||||
inGroupRange: function(mouseX) {
|
||||
var vm = this._view;
|
||||
return (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2);
|
||||
},
|
||||
tooltipPosition: function() {
|
||||
var vm = this._view;
|
||||
if (vm.y < vm.base) {
|
||||
return {
|
||||
x: vm.x,
|
||||
y: vm.y
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
x: vm.x,
|
||||
y: vm.base
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,266 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
// Default config for a category scale
|
||||
var defaultConfig = {
|
||||
display: true,
|
||||
position: "bottom",
|
||||
id: "x-axis-1", // need an ID so datasets can reference the scale
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
show: 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,
|
||||
},
|
||||
|
||||
// label settings
|
||||
labels: {
|
||||
show: true,
|
||||
template: "<%=value%>",
|
||||
fontSize: 12,
|
||||
fontStyle: "normal",
|
||||
fontColor: "#666",
|
||||
fontFamily: "Helvetica Neue",
|
||||
},
|
||||
};
|
||||
|
||||
var DatasetScale = Chart.Element.extend({
|
||||
isHorizontal: function() {
|
||||
return this.options.position == "top" || this.options.position == "bottom";
|
||||
},
|
||||
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
|
||||
if (this.isHorizontal()) {
|
||||
var isRotated = (this.labelRotation > 0);
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
var valueWidth = innerWidth / Math.max((this.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
|
||||
var valueOffset = (valueWidth * index) + this.paddingLeft;
|
||||
|
||||
if (this.options.gridLines.offsetGridLines && includeOffset) {
|
||||
valueOffset += (valueWidth / 2);
|
||||
}
|
||||
|
||||
return this.left + Math.round(valueOffset);
|
||||
} else {
|
||||
return this.top + (index * (this.height / this.data.labels.length));
|
||||
}
|
||||
},
|
||||
getPointPixelForValue: function(value, index, datasetIndex) {
|
||||
return this.getPixelForValue(value, index, datasetIndex, true);
|
||||
},
|
||||
|
||||
// Functions needed for bar charts
|
||||
calculateBaseWidth: function() {
|
||||
return (this.getPixelForValue(null, 1, 0, true) - this.getPixelForValue(null, 0, 0, true)) - (2 * this.options.categorySpacing);
|
||||
},
|
||||
calculateBarWidth: function(datasetCount) {
|
||||
//The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
|
||||
var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * this.options.spacing);
|
||||
|
||||
if (this.options.stacked) {
|
||||
return baseWidth;
|
||||
}
|
||||
return (baseWidth / datasetCount);
|
||||
},
|
||||
calculateBarX: function(datasetCount, datasetIndex, elementIndex) {
|
||||
var xWidth = this.calculateBaseWidth(),
|
||||
xAbsolute = this.getPixelForValue(null, elementIndex, datasetIndex, true) - (xWidth / 2),
|
||||
barWidth = this.calculateBarWidth(datasetCount);
|
||||
|
||||
if (this.options.stacked) {
|
||||
return xAbsolute + barWidth / 2;
|
||||
}
|
||||
|
||||
return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * this.options.spacing) + barWidth / 2;
|
||||
},
|
||||
|
||||
calculateLabelRotation: function(maxHeight, margins) {
|
||||
//Get the width of each grid by calculating the difference
|
||||
//between x offsets between 0 and 1.
|
||||
var labelFont = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily);
|
||||
this.ctx.font = labelFont;
|
||||
|
||||
var firstWidth = this.ctx.measureText(this.data.labels[0]).width;
|
||||
var lastWidth = this.ctx.measureText(this.data.labels[this.data.labels.length - 1]).width;
|
||||
var firstRotated;
|
||||
var lastRotated;
|
||||
|
||||
this.paddingRight = lastWidth / 2 + 3;
|
||||
this.paddingLeft = firstWidth / 2 + 3;
|
||||
|
||||
this.labelRotation = 0;
|
||||
|
||||
if (this.options.display) {
|
||||
var originalLabelWidth = helpers.longestText(this.ctx, labelFont, this.data.labels);
|
||||
var cosRotation;
|
||||
var sinRotation;
|
||||
var firstRotatedWidth;
|
||||
|
||||
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 gridWidth = Math.floor(this.getPixelForValue(0, 1) - this.getPixelForValue(0, 0)) - 6;
|
||||
|
||||
//Max label rotate should be 90 - also act as a loop counter
|
||||
while ((this.labelWidth > gridWidth && this.labelRotation === 0) || (this.labelWidth > gridWidth && this.labelRotation <= 90 && this.labelRotation > 0)) {
|
||||
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.labels.fontSize / 2 > this.yLabelWidth) {
|
||||
this.paddingLeft = firstRotated + this.options.labels.fontSize / 2;
|
||||
}
|
||||
|
||||
this.paddingRight = this.options.labels.fontSize / 2;
|
||||
|
||||
if (sinRotation * originalLabelWidth > 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 (margins) {
|
||||
this.paddingLeft -= margins.left;
|
||||
this.paddingRight -= margins.right;
|
||||
|
||||
this.paddingLeft = Math.max(this.paddingLeft, 0);
|
||||
this.paddingRight = Math.max(this.paddingRight, 0);
|
||||
}
|
||||
|
||||
},
|
||||
// Fit this axis to the given size
|
||||
// @param {number} maxWidth : the max width the axis can be
|
||||
// @param {number} maxHeight: the max height the axis can be
|
||||
// @return {object} minSize : the minimum size needed to draw the axis
|
||||
fit: function(maxWidth, maxHeight, margins) {
|
||||
this.calculateLabelRotation(maxHeight, margins);
|
||||
|
||||
var minSize = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
|
||||
var labelFont = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily);
|
||||
var longestLabelWidth = helpers.longestText(this.ctx, labelFont, this.data.labels);
|
||||
|
||||
// Width
|
||||
if (this.isHorizontal()) {
|
||||
minSize.width = maxWidth;
|
||||
this.width = maxWidth;
|
||||
} else if (this.options.display) {
|
||||
minSize.width = Math.min(longestLabelWidth + 6, maxWidth);
|
||||
}
|
||||
|
||||
// Height
|
||||
if (this.isHorizontal() && this.options.display) {
|
||||
var labelHeight = (Math.cos(helpers.toRadians(this.labelRotation)) * longestLabelWidth) + 1.5 * this.options.labels.fontSize;
|
||||
minSize.height = Math.min(labelHeight, maxHeight);
|
||||
} else if (this.options.display) {
|
||||
minSize.width = Math.min(longestLabelWidth + 6, maxWidth);
|
||||
}
|
||||
|
||||
this.width = minSize.width;
|
||||
this.height = minSize.height;
|
||||
return minSize;
|
||||
},
|
||||
// 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;
|
||||
|
||||
// Make sure we draw text in the correct color
|
||||
this.ctx.fillStyle = this.options.labels.fontColor;
|
||||
|
||||
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;
|
||||
var isRotated = this.labelRotation !== 0;
|
||||
|
||||
helpers.each(this.data.labels, function(label, index) {
|
||||
var xLineValue = this.getPixelForValue(label, index, null, false); // xvalues for grid lines
|
||||
var xLabelValue = this.getPixelForValue(label, index, null, true); // x values for labels (need to consider offsetLabel option)
|
||||
|
||||
if (this.options.gridLines.show) {
|
||||
if (index === 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.labels.show) {
|
||||
this.ctx.save();
|
||||
this.ctx.translate(xLabelValue, (isRotated) ? this.top + 12 : this.top + 8);
|
||||
this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1);
|
||||
this.ctx.font = this.font;
|
||||
this.ctx.textAlign = (isRotated) ? "right" : "center";
|
||||
this.ctx.textBaseline = (isRotated) ? "middle" : "top";
|
||||
this.ctx.fillText(label, 0, 0);
|
||||
this.ctx.restore();
|
||||
}
|
||||
}, this);
|
||||
} else {
|
||||
// Vertical
|
||||
if (this.options.gridLines.show) {}
|
||||
|
||||
if (this.options.labels.show) {
|
||||
// Draw the labels
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Chart.scaleService.registerScaleType("category", DatasetScale, defaultConfig);
|
||||
}).call(this);
|
||||
@@ -0,0 +1,559 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
display: true,
|
||||
position: "left",
|
||||
id: "y-axis-1",
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
show: true,
|
||||
color: "rgba(0, 0, 0, 0.1)",
|
||||
lineWidth: 1,
|
||||
drawOnChartArea: true,
|
||||
drawTicks: true, // draw ticks extending towards the label
|
||||
zeroLineWidth: 1,
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
},
|
||||
|
||||
// scale numbers
|
||||
beginAtZero: false,
|
||||
override: null,
|
||||
|
||||
// label settings
|
||||
labels: {
|
||||
show: true,
|
||||
template: "<%=value.toLocaleString()%>",
|
||||
fontSize: 12,
|
||||
fontStyle: "normal",
|
||||
fontColor: "#666",
|
||||
fontFamily: "Helvetica Neue",
|
||||
}
|
||||
};
|
||||
|
||||
var LinearScale = Chart.Element.extend({
|
||||
calculateRange: helpers.noop, // overridden in the chart. Will set min and max as properties of the scale for later use
|
||||
isHorizontal: function() {
|
||||
return this.options.position == "top" || this.options.position == "bottom";
|
||||
},
|
||||
generateTicks: function(width, height) {
|
||||
// We need to decide how many ticks we are going to have. Each tick draws a grid line.
|
||||
// There are two possibilities. The first is that the user has manually overridden the scale
|
||||
// calculations in which case the job is easy. The other case is that we have to do it ourselves
|
||||
//
|
||||
// We assume at this point that the scale object has been updated with the following values
|
||||
// by the chart.
|
||||
// min: this is the minimum value of the scale
|
||||
// max: this is the maximum value of the scale
|
||||
// options: contains the options for the scale. This is referenced from the user settings
|
||||
// rather than being cloned. This ensures that updates always propogate to a redraw
|
||||
|
||||
// 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.ticks = [];
|
||||
|
||||
if (this.options.override) {
|
||||
// The user has specified the manual override. We use <= instead of < so that
|
||||
// we get the final line
|
||||
for (var i = 0; i <= this.options.override.steps; ++i) {
|
||||
var value = this.options.override.start + (i * this.options.override.stepWidth);
|
||||
ticks.push(value);
|
||||
}
|
||||
} else {
|
||||
// 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(11, Math.ceil(width / 50));
|
||||
} else {
|
||||
// The factor of 2 used to scale the font size has been experimentally determined.
|
||||
maxTicks = Math.min(11, Math.ceil(height / (2 * this.options.labels.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.
|
||||
|
||||
// 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.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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
},
|
||||
buildLabels: function() {
|
||||
// We assume that this has been run after ticks have been generated. We try to figure out
|
||||
// a label for each tick.
|
||||
this.labels = [];
|
||||
|
||||
helpers.each(this.ticks, function(tick, index, ticks) {
|
||||
var label;
|
||||
|
||||
if (this.options.labels.userCallback) {
|
||||
// If the user provided a callback for label generation, use that as first priority
|
||||
label = this.options.labels.userCallback(tick, index, ticks);
|
||||
} else if (this.options.labels.template) {
|
||||
// else fall back to the template string
|
||||
label = helpers.template(this.options.labels.template, {
|
||||
value: tick
|
||||
});
|
||||
}
|
||||
|
||||
this.labels.push(label ? label : ""); // empty string will not render so we're good
|
||||
}, this);
|
||||
},
|
||||
// Get the correct value. If the value type is object get the x or y based on whether we are horizontal or not
|
||||
getRightValue: function(rawValue) {
|
||||
return typeof rawValue === "object" ? (this.isHorizontal() ? rawValue.x : rawValue.y) : rawValue;
|
||||
},
|
||||
getPixelForValue: function(value) {
|
||||
// This must be called after fit has been run so that
|
||||
// this.left, this.top, this.right, and this.bottom have been defined
|
||||
var pixel;
|
||||
var range = this.max - this.min;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
pixel = this.left + (this.width / range * (value - this.min));
|
||||
} else {
|
||||
// Bottom - top since pixels increase downard on a screen
|
||||
pixel = this.bottom - (this.height / range * (value - this.min));
|
||||
}
|
||||
|
||||
return pixel;
|
||||
},
|
||||
|
||||
// Functions needed for line charts
|
||||
calculateRange: function() {
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
|
||||
var positiveValues = [];
|
||||
var negativeValues = [];
|
||||
|
||||
if (this.options.stacked) {
|
||||
helpers.each(this.data.datasets, function(dataset) {
|
||||
if (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id) {
|
||||
helpers.each(dataset.data, function(rawValue, index) {
|
||||
|
||||
var value = this.getRightValue(rawValue);
|
||||
|
||||
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);
|
||||
|
||||
var values = positiveValues.concat(negativeValues);
|
||||
this.min = helpers.min(values);
|
||||
this.max = helpers.max(values);
|
||||
|
||||
} else {
|
||||
helpers.each(this.data.datasets, function(dataset) {
|
||||
if (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id) {
|
||||
helpers.each(dataset.data, function(rawValue, index) {
|
||||
var value = this.getRightValue(rawValue);
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
getPointPixelForValue: function(rawValue, index, datasetIndex) {
|
||||
var value = this.getRightValue(rawValue);
|
||||
|
||||
if (this.options.stacked) {
|
||||
var offsetPos = 0;
|
||||
var offsetNeg = 0;
|
||||
|
||||
for (var i = 0; i < datasetIndex; ++i) {
|
||||
if (this.data.datasets[i].data[index] < 0) {
|
||||
offsetNeg += this.data.datasets[i].data[index];
|
||||
} else {
|
||||
offsetPos += this.data.datasets[i].data[index];
|
||||
}
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
return this.getPixelForValue(offsetNeg + value);
|
||||
} else {
|
||||
return this.getPixelForValue(offsetPos + value);
|
||||
}
|
||||
} else {
|
||||
return this.getPixelForValue(value);
|
||||
}
|
||||
},
|
||||
|
||||
// Functions needed for bar charts
|
||||
calculateBarBase: function(datasetIndex, index) {
|
||||
var base = 0;
|
||||
|
||||
if (this.options.stacked) {
|
||||
|
||||
var value = this.data.datasets[datasetIndex].data[index];
|
||||
|
||||
if (value < 0) {
|
||||
for (var i = 0; i < datasetIndex; i++) {
|
||||
if (this.data.datasets[i].yAxisID === this.id) {
|
||||
base += this.data.datasets[i].data[index] < 0 ? this.data.datasets[i].data[index] : 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var j = 0; j < datasetIndex; j++) {
|
||||
if (this.data.datasets[j].yAxisID === this.id) {
|
||||
base += this.data.datasets[j].data[index] > 0 ? this.data.datasets[j].data[index] : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.getPixelForValue(base);
|
||||
}
|
||||
|
||||
base = this.getPixelForValue(this.min);
|
||||
|
||||
if (this.beginAtZero || ((this.min <= 0 && this.max >= 0) || (this.min >= 0 && this.max <= 0))) {
|
||||
base = this.getPixelForValue(0);
|
||||
base += this.options.gridLines.lineWidth;
|
||||
} else if (this.min < 0 && this.max < 0) {
|
||||
// All values are negative. Use the top as the base
|
||||
base = this.getPixelForValue(this.max);
|
||||
}
|
||||
|
||||
return base;
|
||||
|
||||
},
|
||||
calculateBarY: function(datasetIndex, index) {
|
||||
var value = this.data.datasets[datasetIndex].data[index];
|
||||
|
||||
if (this.options.stacked) {
|
||||
|
||||
var sumPos = 0,
|
||||
sumNeg = 0;
|
||||
|
||||
for (var i = 0; i < datasetIndex; i++) {
|
||||
if (this.data.datasets[i].data[index] < 0) {
|
||||
sumNeg += this.data.datasets[i].data[index] || 0;
|
||||
} else {
|
||||
sumPos += this.data.datasets[i].data[index] || 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
return this.getPixelForValue(sumNeg + value);
|
||||
} else {
|
||||
return this.getPixelForValue(sumPos + value);
|
||||
}
|
||||
|
||||
return this.getPixelForValue(value);
|
||||
}
|
||||
|
||||
var offset = 0;
|
||||
|
||||
for (var j = datasetIndex; j < this.data.datasets.length; j++) {
|
||||
if (j === datasetIndex && value) {
|
||||
offset += value;
|
||||
} else {
|
||||
offset = offset + value;
|
||||
}
|
||||
}
|
||||
|
||||
return this.getPixelForValue(value);
|
||||
},
|
||||
|
||||
// Fit this axis to the given size
|
||||
// @param {number} maxWidth : the max width the axis can be
|
||||
// @param {number} maxHeight: the max height the axis can be
|
||||
// @return {object} minSize : the minimum size needed to draw the axis
|
||||
fit: function(maxWidth, maxHeight) {
|
||||
this.calculateRange();
|
||||
this.generateTicks(maxWidth, maxHeight);
|
||||
this.buildLabels();
|
||||
|
||||
var minSize = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
|
||||
// In a horizontal axis, we need some room for the scale to be drawn
|
||||
//
|
||||
// -----------------------------------------------------
|
||||
// | | | | |
|
||||
//
|
||||
// In a vertical axis, we need some room for the scale to be drawn.
|
||||
// The actual grid lines will be drawn on the chart area, however, we need to show
|
||||
// ticks where the axis actually is.
|
||||
// We will allocate 25px for this width
|
||||
// |
|
||||
// -|
|
||||
// |
|
||||
// |
|
||||
// -|
|
||||
// |
|
||||
// |
|
||||
// -|
|
||||
|
||||
|
||||
// Width
|
||||
if (this.isHorizontal()) {
|
||||
minSize.width = maxWidth; // fill all the width
|
||||
} else {
|
||||
minSize.width = this.options.gridLines.show && this.options.display ? 10 : 0;
|
||||
}
|
||||
|
||||
// height
|
||||
if (this.isHorizontal()) {
|
||||
minSize.height = this.options.gridLines.show && this.options.display ? 10 : 0;
|
||||
} else {
|
||||
minSize.height = maxHeight; // fill all the height
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (this.options.labels.show && this.options.display) {
|
||||
// Don't bother fitting the labels if we are not showing them
|
||||
var labelFont = helpers.fontString(this.options.labels.fontSize,
|
||||
this.options.labels.fontStyle, this.options.labels.fontFamily);
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
// A horizontal axis is more constrained by the height.
|
||||
var maxLabelHeight = maxHeight - minSize.height;
|
||||
var labelHeight = 1.5 * this.options.labels.fontSize;
|
||||
minSize.height = Math.min(maxHeight, minSize.height + labelHeight);
|
||||
} else {
|
||||
// A vertical axis is more constrained by the width. Labels are the dominant factor
|
||||
// here, so get that length first
|
||||
var maxLabelWidth = maxWidth - minSize.width;
|
||||
var largestTextWidth = helpers.longestText(this.ctx, labelFont, this.labels);
|
||||
|
||||
if (largestTextWidth < maxLabelWidth) {
|
||||
// We don't need all the room
|
||||
minSize.width += largestTextWidth;
|
||||
} else {
|
||||
// Expand to max size
|
||||
minSize.width = maxWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.width = minSize.width;
|
||||
this.height = minSize.height;
|
||||
return minSize;
|
||||
},
|
||||
// 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 hasZero;
|
||||
|
||||
// Make sure we draw text in the correct color
|
||||
this.ctx.fillStyle = this.options.labels.fontColor;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
if (this.options.gridLines.show) {
|
||||
// Draw the horizontal line
|
||||
setContextLineSettings = true;
|
||||
hasZero = helpers.findNextWhere(this.ticks, function(tick) {
|
||||
return tick === 0;
|
||||
}) !== undefined;
|
||||
var yTickStart = this.options.position == "bottom" ? this.top : this.bottom - 5;
|
||||
var yTickEnd = this.options.position == "bottom" ? this.top + 5 : this.bottom;
|
||||
|
||||
helpers.each(this.ticks, function(tick, index) {
|
||||
// Grid lines are vertical
|
||||
var xValue = this.getPixelForValue(tick);
|
||||
|
||||
if (tick === 0 || (!hasZero && index === 0)) {
|
||||
// Draw the 0 point specially or the left if there is no 0
|
||||
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;
|
||||
}
|
||||
|
||||
xValue += helpers.aliasPixel(this.ctx.lineWidth);
|
||||
|
||||
// Draw the label area
|
||||
this.ctx.beginPath();
|
||||
|
||||
if (this.options.gridLines.drawTicks) {
|
||||
this.ctx.moveTo(xValue, yTickStart);
|
||||
this.ctx.lineTo(xValue, yTickEnd);
|
||||
}
|
||||
|
||||
// Draw the chart area
|
||||
if (this.options.gridLines.drawOnChartArea) {
|
||||
this.ctx.moveTo(xValue, chartArea.top);
|
||||
this.ctx.lineTo(xValue, chartArea.bottom);
|
||||
}
|
||||
|
||||
// Need to stroke in the loop because we are potentially changing line widths & colours
|
||||
this.ctx.stroke();
|
||||
}, this);
|
||||
}
|
||||
|
||||
if (this.options.labels.show) {
|
||||
// Draw the labels
|
||||
|
||||
var labelStartY;
|
||||
|
||||
if (this.options.position == "top") {
|
||||
labelStartY = this.bottom - 10;
|
||||
this.ctx.textBaseline = "bottom";
|
||||
} else {
|
||||
// bottom side
|
||||
labelStartY = this.top + 10;
|
||||
this.ctx.textBaseline = "top";
|
||||
}
|
||||
|
||||
this.ctx.textAlign = "center";
|
||||
this.ctx.font = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily);
|
||||
|
||||
helpers.each(this.labels, function(label, index) {
|
||||
var xValue = this.getPixelForValue(this.ticks[index]);
|
||||
this.ctx.fillText(label, xValue, labelStartY);
|
||||
}, this);
|
||||
}
|
||||
} else {
|
||||
// Vertical
|
||||
if (this.options.gridLines.show) {
|
||||
|
||||
// Draw the vertical line
|
||||
setContextLineSettings = true;
|
||||
hasZero = helpers.findNextWhere(this.ticks, function(tick) {
|
||||
return tick === 0;
|
||||
}) !== undefined;
|
||||
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(tick, index) {
|
||||
// Grid lines are horizontal
|
||||
var yValue = this.getPixelForValue(tick);
|
||||
|
||||
if (tick === 0 || (!hasZero && index === 0)) {
|
||||
// Draw the 0 point specially or the bottom if there is no 0
|
||||
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; // use boolean to indicate that we only want to do this once
|
||||
}
|
||||
|
||||
yValue += helpers.aliasPixel(this.ctx.lineWidth);
|
||||
|
||||
// Draw the label area
|
||||
this.ctx.beginPath();
|
||||
|
||||
if (this.options.gridLines.drawTicks) {
|
||||
this.ctx.moveTo(xTickStart, yValue);
|
||||
this.ctx.lineTo(xTickEnd, yValue);
|
||||
}
|
||||
|
||||
// Draw the chart area
|
||||
if (this.options.gridLines.drawOnChartArea) {
|
||||
this.ctx.moveTo(chartArea.left, yValue);
|
||||
this.ctx.lineTo(chartArea.right, yValue);
|
||||
}
|
||||
|
||||
this.ctx.stroke();
|
||||
}, this);
|
||||
}
|
||||
|
||||
if (this.options.labels.show) {
|
||||
// Draw the labels
|
||||
|
||||
var labelStartX;
|
||||
|
||||
if (this.options.position == "left") {
|
||||
labelStartX = this.right - 10;
|
||||
this.ctx.textAlign = "right";
|
||||
} else {
|
||||
// right side
|
||||
labelStartX = this.left + 5;
|
||||
this.ctx.textAlign = "left";
|
||||
}
|
||||
|
||||
this.ctx.textBaseline = "middle";
|
||||
this.ctx.font = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily);
|
||||
|
||||
helpers.each(this.labels, function(label, index) {
|
||||
var yValue = this.getPixelForValue(this.ticks[index]);
|
||||
this.ctx.fillText(label, labelStartX, yValue);
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Chart.scaleService.registerScaleType("linear", LinearScale, defaultConfig);
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,445 @@
|
||||
(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: false,
|
||||
|
||||
lineArc: false,
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
show: true,
|
||||
color: "rgba(0, 0, 0, 0.1)",
|
||||
lineWidth: 1,
|
||||
},
|
||||
|
||||
angleLines: {
|
||||
show: true,
|
||||
color: "rgba(0,0,0, 0.1)",
|
||||
lineWidth: 1
|
||||
},
|
||||
|
||||
// scale numbers
|
||||
beginAtZero: true,
|
||||
|
||||
// label settings
|
||||
labels: {
|
||||
show: true,
|
||||
template: "<%=value.toLocaleString()%>",
|
||||
fontSize: 12,
|
||||
fontStyle: "normal",
|
||||
fontColor: "#666",
|
||||
fontFamily: "Helvetica Neue",
|
||||
|
||||
//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.Element.extend({
|
||||
initialize: function() {
|
||||
this.size = helpers.min([this.height, this.width]);
|
||||
this.drawingArea = (this.options.display) ? (this.size / 2) - (this.options.labels.fontSize / 2 + this.options.labels.backdropPaddingY) : (this.size / 2);
|
||||
},
|
||||
update: function() {
|
||||
if (!this.options.lineArc) {
|
||||
this.setScaleSize();
|
||||
} else {
|
||||
this.drawingArea = (this.options.display) ? (this.size / 2) - (this.fontSize / 2 + this.backdropPaddingY) : (this.size / 2);
|
||||
}
|
||||
|
||||
this.buildYLabels();
|
||||
},
|
||||
calculateRange: function() {
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
|
||||
helpers.each(this.data.datasets, function(dataset) {
|
||||
helpers.each(dataset.data, function(value, index) {
|
||||
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);
|
||||
},
|
||||
generateTicks: function() {
|
||||
// We need to decide how many ticks we are going to have. Each tick draws a grid line.
|
||||
// There are two possibilities. The first is that the user has manually overridden the scale
|
||||
// calculations in which case the job is easy. The other case is that we have to do it ourselves
|
||||
//
|
||||
// We assume at this point that the scale object has been updated with the following values
|
||||
// by the chart.
|
||||
// min: this is the minimum value of the scale
|
||||
// max: this is the maximum value of the scale
|
||||
// options: contains the options for the scale. This is referenced from the user settings
|
||||
// rather than being cloned. This ensures that updates always propogate to a redraw
|
||||
|
||||
// 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.ticks = [];
|
||||
|
||||
if (this.options.override) {
|
||||
// The user has specified the manual override. We use <= instead of < so that
|
||||
// we get the final line
|
||||
for (var i = 0; i <= this.options.override.steps; ++i) {
|
||||
var value = this.options.override.start + (i * this.options.override.stepWidth);
|
||||
ticks.push(value);
|
||||
}
|
||||
} else {
|
||||
// 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(11, Math.ceil(this.drawingArea / (2 * this.options.labels.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.
|
||||
|
||||
// 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.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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
},
|
||||
buildYLabels: function() {
|
||||
this.yLabels = [];
|
||||
|
||||
helpers.each(this.ticks, function(tick, index, ticks) {
|
||||
var label;
|
||||
|
||||
if (this.options.labels.userCallback) {
|
||||
// If the user provided a callback for label generation, use that as first priority
|
||||
label = this.options.labels.userCallback(tick, index, ticks);
|
||||
} else if (this.options.labels.template) {
|
||||
// else fall back to the template string
|
||||
label = helpers.template(this.options.labels.template, {
|
||||
value: tick
|
||||
});
|
||||
}
|
||||
|
||||
this.yLabels.push(label ? label : "");
|
||||
}, this);
|
||||
},
|
||||
getCircumference: function() {
|
||||
return ((Math.PI * 2) / this.valuesCount);
|
||||
},
|
||||
setScaleSize: 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.valuesCount; 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(helpers.template(this.options.labels.template, {
|
||||
value: this.labels[i]
|
||||
})).width + 5;
|
||||
if (i === 0 || i === this.valuesCount / 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.valuesCount / 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.valuesCount / 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 = largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2;
|
||||
|
||||
//this.drawingArea = min([maxWidthRadius, (this.height - (2 * (this.pointLabelFontSize + 5)))/2])
|
||||
this.setCenterPoint(radiusReductionLeft, radiusReductionRight);
|
||||
|
||||
},
|
||||
setCenterPoint: function(leftMovement, rightMovement) {
|
||||
|
||||
var maxRight = this.width - rightMovement - this.drawingArea,
|
||||
maxLeft = leftMovement + this.drawingArea;
|
||||
|
||||
this.xCenter = (maxLeft + maxRight) / 2;
|
||||
// Always vertically in the centre as the text height doesn't change
|
||||
this.yCenter = (this.height / 2);
|
||||
},
|
||||
|
||||
getIndexAngle: function(index) {
|
||||
var angleMultiplier = (Math.PI * 2) / this.valuesCount;
|
||||
// Start from the top instead of right, so remove a quarter of the circle
|
||||
|
||||
return index * angleMultiplier - (Math.PI / 2);
|
||||
},
|
||||
getDistanceFromCenterForValue: function(value) {
|
||||
// Take into account half font size + the yPadding of the top value
|
||||
var scalingFactor = this.drawingArea / (this.max - this.min);
|
||||
return (value - this.min) * scalingFactor;
|
||||
},
|
||||
getPointPosition: function(index, distanceFromCenter) {
|
||||
var thisAngle = this.getIndexAngle(index);
|
||||
return {
|
||||
x: (Math.cos(thisAngle) * distanceFromCenter) + this.xCenter,
|
||||
y: (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.yLabels, function(label, index) {
|
||||
// Don't draw a centre value
|
||||
if (index > 0) {
|
||||
var yCenterOffset = this.getDistanceFromCenterForValue(this.ticks[index]);
|
||||
var yHeight = this.yCenter - yCenterOffset;
|
||||
|
||||
// Draw circular lines around the scale
|
||||
if (this.options.gridLines.show) {
|
||||
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.valuesCount; 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.labels.show) {
|
||||
ctx.font = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily);
|
||||
|
||||
if (this.options.labels.showLabelBackdrop) {
|
||||
var labelWidth = ctx.measureText(label).width;
|
||||
ctx.fillStyle = this.options.labels.backdropColor;
|
||||
ctx.fillRect(
|
||||
this.xCenter - labelWidth / 2 - this.options.labels.backdropPaddingX,
|
||||
yHeight - this.fontSize / 2 - this.options.labels.backdropPaddingY,
|
||||
labelWidth + this.options.labels.backdropPaddingX * 2,
|
||||
this.options.labels.fontSize + this.options.labels.backdropPaddingY * 2
|
||||
);
|
||||
}
|
||||
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = this.options.labels.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.valuesCount - 1; i >= 0; i--) {
|
||||
if (this.options.angleLines.show) {
|
||||
var outerPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(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.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.labels.length,
|
||||
halfLabelsCount = this.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.labels[i], pointLabelPosition.x, pointLabelPosition.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Chart.scaleService.registerScaleType("radialLinear", LinearRadialScale, defaultConfig);
|
||||
|
||||
|
||||
}).call(this);
|
||||
Referência em uma Nova Issue
Bloquear um usuário