Comparar commits

..

66 Commits

Autor SHA1 Mensagem Data
Tanner Linsley e8165348db Updated Readme, and versions for beta release 2015-10-24 17:17:13 -06:00
Tanner Linsley a4d11bd1a6 Built Distributables 2015-10-24 16:47:24 -06:00
Tanner Linsley 559ee6291e Merge pull request #1567 from nnnick/fix/rounding
Better linear scale tick formatter + small tick generation
2015-10-24 01:40:43 -06:00
Tanner Linsley 6dc651a79f Merge pull request #1566 from nnnick/v2.0-dev-skip-null-fixes
V2.0 dev skip null fixes
2015-10-24 01:35:42 -06:00
Tanner Linsley 4d009d116d Use the new travis CI docker framework (hopefully) 2015-10-24 01:31:08 -06:00
Tanner Linsley 6adf39e233 radialLinear scale tests now expect rounded values
The rounding problems compounded in a few areas (like the
distanceFromCenter function and drawingArea property).  Those are now
more accurate.
2015-10-24 01:25:00 -06:00
Tanner Linsley e7b71aa909 Line element and controller tests now coincide with the latest skipNull refactor 2015-10-24 01:23:51 -06:00
Tanner Linsley 2cd4b13135 radialLInear getPointPosition now rounds crazy decimals
This particular part of testing was succeeding in chrome, and failing
in firefox.  It should be rounded anyway.
2015-10-24 01:23:13 -06:00
Tanner Linsley 1c40d50097 recursive and accurate getRightValue 2015-10-24 01:22:12 -06:00
etimberg f22c0f3322 Fix tests affected by changes to default label formatter 2015-10-23 22:11:59 -04:00
etimberg 0c3d9ec5dd Improved number format function. Also improved the generation of small tick values 2015-10-23 22:00:59 -04:00
Tanner Linsley ea571003d9 Scale min/max calculations now disregard bad values 2015-10-23 16:41:11 -06:00
Tanner Linsley e50d2f7fc3 Point Skipping now draws properly and is easier to understand 2015-10-23 16:37:34 -06:00
Tanner Linsley 7b13e902ff Bad values for data are now converted to NaN 2015-10-23 16:36:59 -06:00
Tanner Linsley 9d540cebb6 SplineCurve function now graciously handles skipped points 2015-10-23 16:36:33 -06:00
Tanner Linsley afc40e7dbc Radar controller now skips non-numerical coordinates 2015-10-23 16:36:00 -06:00
Tanner Linsley ae0d9b0c68 Line controller now skips non-numerical coordinates 2015-10-23 16:35:52 -06:00
Tanner Linsley 8081e9c801 Bubble controller now skips on non-numerical coordinates 2015-10-23 16:34:40 -06:00
Tanner Linsley 3a20d1187e Merge pull request #1542 from nnnick/v2.0-dev-tooltip-refactor
V2.0 dev tooltip refactor
2015-10-23 13:02:57 -06:00
Tanner Linsley 60f2426774 Only use active datasets in the tooltip body 2015-10-23 12:41:21 -06:00
Tanner Linsley bc41909e7a Track lastTooltipActive for change animations
Since we split up the hover and tooltips modes, both changes need to be
tracked for visual updates between the two.
2015-10-23 12:41:21 -06:00
Tanner Linsley 7a042bc7eb Merge pull request #1559 from posgarou/bugfix/chart_undefined_in_core_helper
Fix mistaken variable assignment in core files
2015-10-22 12:04:16 -06:00
Ryan Mitchell 57979a2270 Fix similar typos in core.controller & element 2015-10-22 12:47:45 -04:00
Ryan Mitchell ef1c4fb0cb Fix typo in core.helpers.js 2015-10-22 12:41:03 -04:00
etimberg 965d74e34a Time scale test fix for optional labels 2015-10-21 21:00:13 -04:00
etimberg 854c1af45e test fix 2015-10-21 20:47:22 -04:00
etimberg 24e8fe3a4b Merge remote-tracking branch 'origin/v2.0-dev' into v2.0-dev-tooltip-refactor 2015-10-21 20:18:23 -04:00
Tanner Linsley 511e82abb9 Merge pull request #1551 from nnnick/travis-unit-test
Unit tests work better with Travis
2015-10-20 18:38:27 -06:00
etimberg e46a2cb074 Fix JSHint errors 2015-10-20 20:33:51 -04:00
Evert Timberg 351ccaf2f2 Fix 2 test fails 2015-10-20 20:12:56 -04:00
Evert Timberg 2e77651dd2 Test in firefox on travis 2015-10-20 20:08:41 -04:00
Tanner Linsley 35011e5ae3 Support min and max dates on time scale 2015-10-19 21:23:01 -06:00
etimberg bfabac945f Labels are now optional for the time scale. 2015-10-19 19:20:08 -04:00
Evert Timberg 5495a34d02 Fix 2 fails due to a bug fix for the scale label colour. 2015-10-18 19:57:06 -04:00
Evert Timberg d0475b8052 Down to 3 test failures 2015-10-18 19:48:57 -04:00
Evert Timberg 86a52d0302 Fix some test failures 2015-10-18 19:34:56 -04:00
etimberg 2b057cf690 Merge remote-tracking branch 'origin/v2.0-dev' into v2.0-dev-tooltip-refactor 2015-10-18 18:17:39 -04:00
etimberg 082391e385 Update docs a bit for new items. Small updates for tooltip labels. 2015-10-18 18:14:56 -04:00
etimberg 7603b3cc36 Time scales now support passing in data as points. Added this to the time scale sample file. 2015-10-18 18:00:46 -04:00
etimberg ceaa4ff03f Add a helper function to reduce code size 2015-10-18 16:31:18 -04:00
etimberg 180209e55c Factor out getLabelForIndex into each scale so we can return appropriate data based on the scale type 2015-10-18 16:13:57 -04:00
etimberg f650445ddc Use correct function to get afterBody lines for tooltip. 2015-10-18 10:39:54 -04:00
Tanner Linsley 19a7c57e2f All tooltip callbacks support arrays for lines, and no drawing invisible tooltips.
Simply return a string for a single line tooltip, or return an array to
create multiple lines.
2015-10-17 15:53:33 -06:00
Evert Timberg 9526c77675 Merge pull request #1512 from nnnick/v2.0-dev-bubble-controller
Bubble Chart Type and Bubble Controller
2015-10-17 08:46:44 -04:00
Evert Timberg 3d6ff09847 Merge pull request #1541 from nnnick/v2.0-dev-testing-fixes
Testing fixes for time scale
2015-10-17 08:30:37 -04:00
Tanner Linsley e0918817ae Testing fixes for time scale 2015-10-16 21:14:07 -06:00
Tanner Linsley cb9860e9e0 Merge pull request #1540 from nnnick/fix/scale-tick-font-size
Draw scale ticks using correct font
2015-10-16 20:48:46 -06:00
etimberg 3699addf16 Use the correct font for the ticks. Ensure that scale labels fill in the correct colour. 2015-10-16 22:00:43 -04:00
Evert Timberg 04a0204119 Merge pull request #1538 from lpaluszk/v2.0-dev
Fix HTMLIframeElement remove/removeNode issue in removeResizeListener…
2015-10-16 21:25:34 -04:00
Lucas Styles 4a48e19cac Fix HTMLIframeElement remove/removeNode issue in removeResizeListener method 2015-10-17 00:35:47 +01:00
Tanner Linsley 6c4c4695d9 Merge pull request #1526 from etimberg/fix/responsive-config-setting
Use the correct merged responsive setting in the resize listener
2015-10-13 11:46:14 -06:00
Evert Timberg e39298db3c Before labels can rotate, we need the appropriate left, right, top, & bottom attributes of the scale set with default values so that tick spacing can be determined. After ensuring that this happens, tests needed to be updated. Added unit testing for the scale service. 2015-10-13 11:43:00 -04:00
Evert Timberg 6001a1e4e7 Fix JSHint task 2015-10-13 10:33:59 -04:00
Tanner Linsley b835d5f209 Tooltip Hooks 2015-10-12 14:51:00 -06:00
Tanner Linsley 3da66ba42e Merge pull request #1525 from etimberg/fix/scale-merge
Merge scale settings at the correct time
2015-10-12 11:51:21 -06:00
Evert Timberg 93ee8f85f6 Put comment back in correct spot 2015-10-12 09:19:14 -04:00
Evert Timberg 1232ca53f0 Fix a race condition in the resize listener & use the correct merged config object for the responsive setting 2015-10-12 09:16:49 -04:00
Evert Timberg a756e0de15 Only merge scale defaults with the global scale defaults when getting the scale defaults. Otherwise, the user does not have the ability to change them via the global settings since registration occurs when the library is loaded. 2015-10-12 08:58:03 -04:00
Tanner Linsley 81095e777a Merge pull request #1517 from nnnick/feature/hide-datasets
Now allows hiding individual datasets
2015-10-07 21:51:15 -06:00
Evert Timberg 0d2fa807da Update samples with some hidden datasets 2015-10-07 19:54:53 -04:00
Evert Timberg b36c8ff788 Update controllers to handle datasets that are not visible 2015-10-07 19:54:11 -04:00
Evert Timberg aaec5efd52 Scales will only consider visible datasets when calculating data max and min values 2015-10-07 19:37:53 -04:00
Evert Timberg 22e7934804 Helper to determine if a dataset is visible or not 2015-10-07 19:10:10 -04:00
Tanner Linsley ef5cec7f5e Tooltips now using new lineArray format 2015-10-06 20:40:25 -06:00
Tanner Linsley 65f9ee8a4a Bubble Chart Type and Bubble Controller 2015-10-05 12:40:28 -06:00
Tanner Linsley 0ac59b8a42 Update README.md 2015-09-30 15:32:16 -06:00
56 arquivos alterados com 3836 adições e 1430 exclusões
+6
Ver Arquivo
@@ -3,6 +3,10 @@ node_js:
- "0.11"
- "0.10"
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
before_script:
- npm install
@@ -11,3 +15,5 @@ script:
notifications:
slack: chartjs:pcfCZR6ugg5TEcaLtmIfQYuA
sudo: false
externo
+1134 -567
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+7 -6
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+24 -1
Ver Arquivo
@@ -2,10 +2,33 @@
[![Build Status](https://travis-ci.org/nnnick/Chart.js.svg?branch=v2.0-dev)](https://travis-ci.org/nnnick/Chart.js) [![Code Climate](https://codeclimate.com/github/nnnick/Chart.js/badges/gpa.svg)](https://codeclimate.com/github/nnnick/Chart.js)
# 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)
## v2.0 Beta
Current Release: [2.0.0-beta](https://github.com/nnnick/Chart.js/releases/tag/2.0.0-beta)
The next generation and release of Chart.js has been well under way this year and we are very close to releasing some amazing new features including, but not limited to:
- Rewritten, optimized, and unit-tested
- New and improved scales (log, time, linear, category, multiple scales)
- Improved responsiveness and resizing
- Powerful support for adding, removing, changing, and updating data on the fly
- Animations on all elements, colors and tooltips
- Powerful customization when you need it. Automatic and dynamic when you don't.
- Excellent support for modern frameworks and modular build systems.
- Even more extensible via new element controllers, combo chart support, and hook system
- Bug fixes not addressed in 1.x, and much, much more...
#####Contributing to 2.0
Submit PR's to the v2.0-dev branch.
#####Building and Testing
`gulp build`, `gulp test`
## v1.x Status: Feature Complete
We are now treating v1.x as feature complete. PR's for bug fixes are welcome, but we urge any open PR's for v1.x features to be refactored and resubmitted for v2.x (if the feature has not already been implemented).
## Documentation
You can find documentation at [chartjs.org/docs](http://www.chartjs.org/docs/). The markdown files that build the site are available under `/docs`. Please note - in some of the json examples of configuration you might notice some liquid tags - this is just for the generating the site html, please disregard.
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
{
"name": "Chart.js",
"version": "2.0.0-alpha",
"version": "2.0.0-beta",
"description": "Simple HTML5 Charts using the canvas element",
"homepage": "https://github.com/nnnick/Chart.js",
"author": "nnnick",
+48 -14
Ver Arquivo
@@ -101,8 +101,22 @@ Chart.defaults.global = {
// Element defaults defined in element extensions
elements: {},
// Legend template string
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i = 0; i < data.datasets.length; i++){%><li><span style=\"background-color:<%=data.datasets[i].backgroundColor%>\"><%if(data.datasets[i].label){%><%=data.datasets[i].label%><%}%></span></li><%}%></ul>",
// Legend callback function.
// @param {Chart} chart : the chart object to generate a legend for
legendCallback: legendCallback: function(chart) {
var text = [];
text.push('<ul class="' + chart.id + '-legend">');
for (var i = 0; i < chart.data.datasets.length; i++) {
text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '">');
if (chart.data.datasets[i].label) {
text.push(chart.data.datasets[i].label);
}
text.push('</span></li>');
}
text.push('</ul>');
return text.join("");
}
animation: {
duration: 1000,
@@ -128,18 +142,38 @@ Chart.defaults.global = {
caretSize: 8,
cornerRadius: 6,
xOffset: 10,
template: [
'<% if(label){ %>',
'<%=label %>: ',
'<% } %>',
'<%=value %>',
].join(''),
multiTemplate: [
'<%if (datasetLabel){ %>',
'<%=datasetLabel %>: ',
'<% } %>',
'<%=value %>'
].join(''),
// V2.0 introduces callback functions as a replacement for the template engine in v1. The tooltip
// has the following callbacks for providing text. For all functions, 'this' will be the tooltip object
// create from the Chart.Tooltip constructor
//
// All functions are called with the same arguments
// - xLabel : string or array of strings. This is the xDataValue for each item to be displayed in the tooltip
// - yLabel : string or array of strings. This is the yDataValue for each item to be displayed in the tooltip
// - index : number. Data index
// - datasetIndex : number. Dataset index
// - data : object. Data object passed to chart
callbacks: {
beforeTitle: helpers.noop,
title: function(xLabel, yLabel, index, datasetIndex, data) {
// If there are multiple items, use the xLabel of the
return helpers.isArray(xLabel) ? xLabel[0] : xLabel;
},
afterTitle: helpers.noop,
beforeBody: helpers.noop,
beforeLabel: helpers.noop,
label: function(xLabel, yLabel, index, datasetIndex, data) {
return this._data.datasets[datasetIndex].label + ': ' + yLabel;
},
afterLabel: helpers.noop,
afterBody: helpers.noop,
beforeFooter: helpers.noop,
footer: helpers.noop,
afterFooter: helpers.noop,
},
multiKeyBackground: '#fff',
},
+9 -3
Ver Arquivo
@@ -36,8 +36,11 @@ var srcFiles = [
'./src/charts/**',
];
var testFiles = [
var preTestFiles = [
'./node_modules/moment/min/moment.min.js',
];
var testFiles = [
'./test/mockContext.js',
'./test/*.js'
];
@@ -117,7 +120,7 @@ function releaseTask() {
function jshintTask() {
return gulp.src(srcDir + '*.js')
return gulp.src(srcDir + '**/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
}
@@ -131,17 +134,19 @@ function validHTMLTask() {
function unittestTask() {
var files = srcFiles.slice();
Array.prototype.unshift.apply(files, preTestFiles);
Array.prototype.push.apply(files, testFiles);
return gulp.src(files)
.pipe(karma({
configFile: 'karma.conf.js',
configFile: 'karma.conf.ci.js',
action: 'run'
}));
}
function unittestWatchTask() {
var files = srcFiles.slice();
Array.prototype.unshift.apply(files, preTestFiles);
Array.prototype.push.apply(files, testFiles);
return gulp.src(files)
@@ -153,6 +158,7 @@ function unittestWatchTask() {
function coverageTask() {
var files = srcFiles.slice();
Array.prototype.unshift.apply(files, preTestFiles);
Array.prototype.push.apply(files, testFiles);
return gulp.src(files)
+7
Ver Arquivo
@@ -0,0 +1,7 @@
module.exports = function(config) {
config.set({
browsers: ['Firefox'],
frameworks: ['jasmine'],
reporters: ['progress', 'html'],
});
};
+1 -2
Ver Arquivo
@@ -2,13 +2,12 @@
"name": "chart.js",
"homepage": "http://www.chartjs.org",
"description": "Simple HTML5 charts using the canvas element.",
"version": "2.0.0-alpha",
"version": "2.0.0-beta",
"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",
+1
Ver Arquivo
@@ -45,6 +45,7 @@
backgroundColor: "rgba(220,220,220,0.5)",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
}, {
hidden: true,
label: 'Dataset 2',
backgroundColor: "rgba(151,187,205,0.5)",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
+206
Ver Arquivo
@@ -0,0 +1,206 @@
<!doctype html>
<html>
<head>
<title>Bar Chart</title>
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
<script src="../Chart.js"></script>
<style type="text/css">
canvas {
border: 1px solid red;
}
</style>
</head>
<body>
<div id="container" style="width: 100%; height: 25%;">
<canvas id="canvas"></canvas>
</div>
<button id="randomizeData">Randomize Data</button>
<button id="addDataset">Add Dataset</button>
<button id="removeDataset">Remove Dataset</button>
<button id="addData">Add Data</button>
<button id="removeData">Remove Data</button>
<button id="show">Show</button>
<div>
<h3>Legend</h3>
<div id="legendContainer">
</div>
</div>
<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 bubbleChartData = {
animation: {
duration: 10000
},
datasets: [{
label: "My First dataset",
backgroundColor: randomColor(),
data: [{
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}]
}, {
label: "My Second dataset",
backgroundColor: randomColor(),
data: [{
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}]
}]
};
function updateLegend() {
$legendContainer = $('#legendContainer');
$legendContainer.empty();
$legendContainer.append(window.myChart.generateLegend());
}
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myChart = new Chart(ctx, {
type: 'bubble',
data: bubbleChartData,
options: {
responsive: true,
}
});
updateLegend();
};
$('#randomizeData').click(function() {
var zero = Math.random() < 0.2 ? true : false;
$.each(bubbleChartData.datasets, function(i, dataset) {
dataset.backgroundColor = randomColor();
dataset.data = dataset.data.map(function() {
return {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
};
});
});
window.myChart.update();
updateLegend();
});
$('#addDataset').click(function() {
var newDataset = {
backgroundColor: randomColor(),
data: []
};
for (var index = 0; index < bubbleChartData.datasets[0].data.length; ++index) {
newDataset.data.push({
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
});
}
bubbleChartData.datasets.push(newDataset);
window.myChart.update();
updateLegend();
});
$('#addData').click(function() {
if (bubbleChartData.datasets.length > 0) {
for (var index = 0; index < bubbleChartData.datasets.length; ++index) {
//window.myChart.addData(randomScalingFactor(), index);
bubbleChartData.datasets[index].data.push({
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
});
}
window.myChart.update();
updateLegend();
}
});
$('#removeDataset').click(function() {
bubbleChartData.datasets.splice(0, 1);
window.myChart.update();
updateLegend();
});
$('#removeData').click(function() {
bubbleChartData.datasets.forEach(function(dataset, datasetIndex) {
dataset.data.pop();
});
window.myChart.update();
updateLegend();
});
$('#show').click(function() {
document.getElementById('container').style.display = '';
});
</script>
</body>
</html>
+3 -3
Ver Arquivo
@@ -2,7 +2,7 @@
<html>
<head>
<title>Bar Chart</title>
<title>Combo Bar-Line Chart</title>
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
<script src="../Chart.js"></script>
</head>
@@ -30,14 +30,14 @@
borderColor: 'white',
borderWidth: 2
}, {
type: 'bar',
type: 'line',
label: 'Dataset 2',
backgroundColor: "rgba(151,187,205,0.5)",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
borderColor: 'white',
borderWidth: 2
}, {
type: 'line',
type: 'bar',
label: 'Dataset 3',
backgroundColor: "rgba(220,220,220,0.5)",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
+1
Ver Arquivo
@@ -61,6 +61,7 @@
"#4D5360",
],
}, {
hidden: true,
data: [
randomScalingFactor(),
randomScalingFactor(),
+164
Ver Arquivo
@@ -0,0 +1,164 @@
<!doctype html>
<html>
<head>
<title>Time Scale Point Data</title>
<script src="../node_modules/moment/min/moment.min.js"></script>
<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>
<body>
<div style="width:100%;">
<canvas id="canvas" style="width:100%;height:100%"></canvas>
</div>
<br>
<br>
<button id="randomizeData">Randomize Data</button>
<button id="addData">Add Data</button>
<button id="removeData">Remove Data</button>
<div>
<h3>Legend</h3>
<div id="legendContainer">
</div>
</div>
<script>
var randomScalingFactor = function() {
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
};
var randomColorFactor = function() {
return Math.round(Math.random() * 255);
};
var randomColor = function(opacity) {
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
};
var newDate = function(days) {
var date = new Date();
return date.setDate(date.getDate() + days);
};
var newTimestamp = function(days) {
return Date.now() - days * 100000;
};
var config = {
type: 'line',
data: {
datasets: [{
label: "Dataset with point data",
data: [{
x: "12/31/2014 06:00",
y: randomScalingFactor()
}, {
x: "01/04/2015 13:00",
y: randomScalingFactor()
}, {
x: "01/07/2015 01:15",
y: randomScalingFactor()
}, {
x: "01/15/2015 01:15",
y: randomScalingFactor()
}],
fill: false
}]
},
options: {
responsive: true,
scales: {
xAxes: [{
type: "time",
display: true,
time: {
format: 'MM/DD/YYYY HH:mm',
// round: 'day'
},
scaleLabel: {
show: true,
labelString: 'Date'
}
}, ],
yAxes: [{
display: true,
scaleLabel: {
show: true,
labelString: 'value'
}
}]
},
elements: {
line: {
tension: 0.3
}
},
}
};
$.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, config);
updateLegend();
};
function updateLegend() {
$legendContainer = $('#legendContainer');
$legendContainer.empty();
$legendContainer.append(window.myLine.generateLegend());
}
$('#randomizeData').click(function() {
$.each(config.data.datasets, function(i, dataset) {
dataset.data = dataset.data.map(function() {
return randomScalingFactor();
});
});
window.myLine.update();
updateLegend();
});
$('#addData').click(function() {
if (config.data.datasets.length > 0) {
var newTime = myLine.scales['x-axis-0'].labelMoments[0][myLine.scales['x-axis-0'].labelMoments[0].length - 1]
.clone()
.add(1, 'day')
.format('MM/DD/YYYY HH:mm');
for (var index = 0; index < config.data.datasets.length; ++index) {
config.data.datasets[index].data.push({
x: newTime,
y: randomScalingFactor()
});
}
window.myLine.update();
updateLegend();
}
});
$('#removeData').click(function() {
config.data.datasets.forEach(function(dataset, datasetIndex) {
dataset.data.pop();
});
window.myLine.update();
updateLegend();
});
</script>
</body>
</html>
+16
Ver Arquivo
@@ -63,6 +63,22 @@
}, {
label: "My Second dataset",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
}, {
label: "Dataset with point data",
data: [{
x: "12/31/2014 06:00",
y: randomScalingFactor()
}, {
x: "01/04/2015 13:00",
y: randomScalingFactor()
}, {
x: "01/07/2015 01:15",
y: randomScalingFactor()
}, {
x: "01/15/2015 01:15",
y: randomScalingFactor()
}],
fill: false
}]
},
options: {
+2 -2
Ver Arquivo
@@ -54,8 +54,8 @@
xAxes: [{
display: true,
ticks: {
callback: function(dataLabel, index) {
return dataLabel;
userCallback: function(dataLabel, index) {
return index % 2 === 0 ? dataLabel : '';
}
}
}],
+34 -1
Ver Arquivo
@@ -13,7 +13,7 @@
</head>
<body>
<div style="width:50%;">
<div style="width:100%;">
<canvas id="canvas" style="width:100%;height:100%"></canvas>
</div>
<br>
@@ -48,6 +48,10 @@
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
fill: false,
borderDash: [5, 5],
}, {
hidden: true,
label: 'hidden dataset',
data: [],
}, {
label: "My Second dataset",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
@@ -55,6 +59,35 @@
},
options: {
responsive: true,
tooltips: {
mode: 'label',
callbacks: {
// beforeTitle: function() {
// return '...beforeTitle';
// },
// afterTitle: function() {
// return '...afterTitle';
// },
// beforeBody: function() {
// return '...beforeBody';
// },
// afterBody: function() {
// return '...afterBody';
// },
// beforeFooter: function() {
// return '...beforeFooter';
// },
// footer: function() {
// return 'Footer';
// },
// afterFooter: function() {
// return '...afterFooter';
// },
}
},
hover: {
mode: 'label'
},
scales: {
xAxes: [{
display: true,
+5 -1
Ver Arquivo
@@ -42,6 +42,10 @@
backgroundColor: "rgba(220,220,220,0.2)",
pointBackgroundColor: "rgba(220,220,220,1)",
data: [null, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
}, {
label: 'Hidden dataset',
hidden: true,
data: [],
}, {
label: "My Second dataset",
backgroundColor: "rgba(151,187,205,0.2)",
@@ -49,7 +53,7 @@
hoverPointBackgroundColor: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: [null, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
}]
},]
},
options: {
scale: {
+191
Ver Arquivo
@@ -0,0 +1,191 @@
<!doctype html>
<html>
<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>
<body>
<div style="width:100%;">
<canvas id="canvas" style="width:100%;height:100%"></canvas>
</div>
<br>
<br>
<button id="randomizeData">Randomize Data</button>
<button id="addDataset">Add Dataset</button>
<button id="removeDataset">Remove Dataset</button>
<button id="addData">Add Data</button>
<button id="removeData">Remove Data</button>
<div>
<h3>Legend</h3>
<div id="legendContainer">
</div>
</div>
<script>
var randomScalingFactor = function() {
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
};
var randomColorFactor = function() {
return Math.round(Math.random() * 255);
};
var randomColor = function(opacity) {
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
};
var config = {
type: 'line',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
fill: false,
borderDash: [5, 5],
}, {
label: "My Second dataset",
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
}]
},
options: {
responsive: true,
tooltips: {
mode: 'label',
callbacks: {
beforeTitle: function() {
return '...beforeTitle';
},
afterTitle: function() {
return '...afterTitle';
},
beforeBody: function() {
return '...beforeBody';
},
afterBody: function() {
return '...afterBody';
},
beforeFooter: function() {
return '...beforeFooter';
},
footer: function() {
return 'Footer';
},
afterFooter: function() {
return '...afterFooter';
},
}
},
hover: {
mode: 'label'
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
show: true,
labelString: 'Month'
}
}],
yAxes: [{
display: true,
scaleLabel: {
show: true,
labelString: 'Value'
}
}]
}
}
};
$.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;
});
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myLine = new Chart(ctx, config);
updateLegend();
};
function updateLegend() {
$legendContainer = $('#legendContainer');
$legendContainer.empty();
$legendContainer.append(window.myLine.generateLegend());
}
$('#randomizeData').click(function() {
$.each(config.data.datasets, function(i, dataset) {
dataset.data = dataset.data.map(function() {
return randomScalingFactor();
});
});
window.myLine.update();
updateLegend();
});
$('#addDataset').click(function() {
var newDataset = {
label: 'Dataset ' + config.data.datasets.length,
borderColor: randomColor(0.4),
backgroundColor: randomColor(0.5),
pointBorderColor: randomColor(0.7),
pointBackgroundColor: randomColor(0.5),
pointBorderWidth: 1,
data: [],
};
for (var index = 0; index < config.data.labels.length; ++index) {
newDataset.data.push(randomScalingFactor());
}
config.data.datasets.push(newDataset);
window.myLine.update();
updateLegend();
});
$('#addData').click(function() {
if (config.data.datasets.length > 0) {
config.data.labels.push('dataset #' + config.data.labels.length);
$.each(config.data.datasets, function(i, dataset) {
dataset.data.push(randomScalingFactor());
});
window.myLine.update();
updateLegend();
}
});
$('#removeDataset').click(function() {
config.data.datasets.splice(0, 1);
window.myLine.update();
updateLegend();
});
$('#removeData').click(function() {
config.data.labels.splice(-1, 1); // remove the label first
config.data.datasets.forEach(function(dataset, datasetIndex) {
dataset.data.pop();
});
window.myLine.update();
updateLegend();
});
</script>
</body>
</html>
+39
Ver Arquivo
@@ -0,0 +1,39 @@
(function() {
"use strict";
var root = this;
var Chart = root.Chart;
var helpers = Chart.helpers;
var defaultConfig = {
hover: {
mode: 'single',
},
scales: {
xAxes: [{
type: "linear", // bubble should probably use a linear scale by default
position: "bottom",
id: "x-axis-0", // need an ID so datasets can reference the scale
}],
yAxes: [{
type: "linear",
position: "left",
id: "y-axis-0",
}],
},
tooltips: {
template: "(<%= value.x %>, <%= value.y %>)",
multiTemplate: "<%if (datasetLabel){%><%=datasetLabel%>: <%}%>(<%= value.x %>, <%= value.y %>)",
},
};
Chart.Bubble = function(context, config) {
config.options = helpers.configMerge(defaultConfig, config.options);
config.type = 'bubble';
return new Chart(context, config);
};
}).call(this);
+1 -1
Ver Arquivo
@@ -15,6 +15,6 @@
config.type = 'doughnut';
return new Chart(context, config);
}
};
}).call(this);
+1 -1
Ver Arquivo
@@ -9,6 +9,6 @@
config.type = 'line';
return new Chart(context, config);
}
};
}).call(this);
+1 -1
Ver Arquivo
@@ -15,6 +15,6 @@
config.type = 'polarArea';
return new Chart(context, config);
}
};
}).call(this);
+1 -1
Ver Arquivo
@@ -14,6 +14,6 @@
config.type = 'radar';
return new Chart(context, config);
}
};
}).call(this);
+1 -1
Ver Arquivo
@@ -34,6 +34,6 @@
config.options = helpers.configMerge(defaultConfig, config.options);
config.type = 'line';
return new Chart(context, config);
}
};
}).call(this);
+40 -20
Ver Arquivo
@@ -66,15 +66,15 @@
// Get the number of datasets that display bars. We use this to correctly calculate the bar width
getBarCount: function getBarCount() {
var barCount = 0;
helpers.each(this.chart.data.datasets, function(dataset) {
if (dataset.type === 'bar') {
++barCount;
} else if (dataset.type === undefined && this.chart.config.type === 'bar') {
++barCount;
if (helpers.isDatasetVisible(dataset)) {
if (dataset.type === 'bar') {
++barCount;
} else if (dataset.type === undefined && this.chart.config.type === 'bar') {
++barCount;
}
}
}, this);
return barCount;
},
@@ -192,14 +192,16 @@
if (value < 0) {
for (var i = 0; i < datasetIndex; i++) {
if (this.chart.data.datasets[i].yAxisID === yScale.id) {
base += this.chart.data.datasets[i].data[index] < 0 ? this.chart.data.datasets[i].data[index] : 0;
var negDS = this.chart.data.datasets[i];
if (helpers.isDatasetVisible(negDS) && negDS.yAxisID === yScale.id) {
base += negDS.data[index] < 0 ? negDS.data[index] : 0;
}
}
} else {
for (var j = 0; j < datasetIndex; j++) {
if (this.chart.data.datasets[j].yAxisID === yScale.id) {
base += this.chart.data.datasets[j].data[index] > 0 ? this.chart.data.datasets[j].data[index] : 0;
var posDS = this.chart.data.datasets[j];
if (helpers.isDatasetVisible(posDS) && posDS.yAxisID === yScale.id) {
base += posDS.data[index] > 0 ? posDS.data[index] : 0;
}
}
}
@@ -225,10 +227,11 @@
var xScale = this.getScaleForID(this.getDataset().xAxisID);
var yScale = this.getScaleForID(this.getDataset().yAxisID);
var datasetCount = !this.chart.isCombo ? this.chart.data.datasets.length : helpers.where(this.chart.data.datasets, function(ds) {
/*var datasetCount = !this.chart.isCombo ? this.chart.data.datasets.length : helpers.where(this.chart.data.datasets, function(ds) {
return ds.type == 'bar';
}).length;
}).length;*/
var datasetCount = this.getBarCount();
var tickWidth = (function() {
var min = xScale.getPixelForValue(null, 1) - xScale.getPixelForValue(null, 0);
for (var i = 2; i < this.getDataset().data.length; i++) {
@@ -266,14 +269,28 @@
},
// Get bar index from the given dataset index accounting for the fact that not all bars are visible
getBarIndex: function(datasetIndex) {
var barIndex = 0;
for (var j = 0; j < datasetIndex; ++j) {
if (helpers.isDatasetVisible(this.chart.data.datasets[j]) &&
(this.chart.data.datasets[j].type === 'bar' || (this.chart.data.datasets[j].type === undefined && this.chart.config.type === 'bar'))) {
++barIndex;
}
}
return barIndex;
},
calculateBarX: function(index, datasetIndex) {
var yScale = this.getScaleForID(this.getDataset().yAxisID);
var xScale = this.getScaleForID(this.getDataset().xAxisID);
var barIndex = this.getBarIndex(datasetIndex);
var ruler = this.getRuler();
var leftTick = xScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo);
var leftTick = xScale.getPixelForValue(null, index, barIndex, this.chart.isCombo);
leftTick -= this.chart.isCombo ? (ruler.tickWidth / 2) : 0;
if (yScale.options.stacked) {
@@ -283,9 +300,9 @@
return leftTick +
(ruler.barWidth / 2) +
ruler.categorySpacing +
(ruler.barWidth * datasetIndex) +
(ruler.barWidth * barIndex) +
(ruler.barSpacing / 2) +
(ruler.barSpacing * datasetIndex);
(ruler.barSpacing * barIndex);
},
calculateBarY: function(index, datasetIndex) {
@@ -301,10 +318,13 @@
sumNeg = 0;
for (var i = 0; i < datasetIndex; i++) {
if (this.chart.data.datasets[i].data[index] < 0) {
sumNeg += this.chart.data.datasets[i].data[index] || 0;
} else {
sumPos += this.chart.data.datasets[i].data[index] || 0;
var ds = this.chart.data.datasets[i];
if (helpers.isDatasetVisible(ds)) {
if (ds.data[index] < 0) {
sumNeg += ds.data[index] || 0;
} else {
sumPos += ds.data[index] || 0;
}
}
}
+219
Ver Arquivo
@@ -0,0 +1,219 @@
(function() {
"use strict";
var root = this,
Chart = root.Chart,
helpers = Chart.helpers;
Chart.defaults.bubble = {
hover: {
mode: "single"
},
scales: {
xAxes: [{
type: "linear", // bubble should probably use a linear scale by default
position: "bottom",
id: "x-axis-0", // need an ID so datasets can reference the scale
}],
yAxes: [{
type: "linear",
position: "left",
id: "y-axis-0",
}],
},
tooltips: {
template: "(<%= value.x %>, <%= value.y %>, <%= value.r %>)",
multiTemplate: "<%if (datasetLabel){%><%=datasetLabel%>: <%}%>(<%= value.x %>, <%= value.y %>, <%= value.r %>)",
},
};
Chart.controllers.bubble = function(chart, datasetIndex) {
this.initialize.call(this, chart, datasetIndex);
};
helpers.extend(Chart.controllers.bubble.prototype, {
initialize: function(chart, datasetIndex) {
this.chart = chart;
this.index = datasetIndex;
this.linkScales();
this.addElements();
},
updateIndex: function(datasetIndex) {
this.index = datasetIndex;
},
linkScales: function() {
if (!this.getDataset().xAxisID) {
this.getDataset().xAxisID = this.chart.options.scales.xAxes[0].id;
}
if (!this.getDataset().yAxisID) {
this.getDataset().yAxisID = this.chart.options.scales.yAxes[0].id;
}
},
getDataset: function() {
return this.chart.data.datasets[this.index];
},
getScaleForId: function(scaleID) {
return this.chart.scales[scaleID];
},
addElements: function() {
this.getDataset().metaData = this.getDataset().metaData || [];
helpers.each(this.getDataset().data, function(value, index) {
this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({
_chart: this.chart.chart,
_datasetIndex: this.index,
_index: index,
});
}, this);
},
addElementAndReset: function(index) {
this.getDataset().metaData = this.getDataset().metaData || [];
var point = new Chart.elements.Point({
_chart: this.chart.chart,
_datasetIndex: this.index,
_index: index,
});
// Reset the point
this.updateElement(point, index, true);
// Add to the points array
this.getDataset().metaData.splice(index, 0, point);
},
removeElement: function(index) {
this.getDataset().metaData.splice(index, 1);
},
reset: function() {
this.update(true);
},
buildOrUpdateElements: function buildOrUpdateElements() {
// Handle the number of data points changing
var numData = this.getDataset().data.length;
var numPoints = this.getDataset().metaData.length;
// Make sure that we handle number of datapoints changing
if (numData < numPoints) {
// Remove excess bars for data points that have been removed
this.getDataset().metaData.splice(numData, numPoints - numData);
} else if (numData > numPoints) {
// Add new elements
for (var index = numPoints; index < numData; ++index) {
this.addElementAndReset(index);
}
}
},
update: function update(reset) {
var points = this.getDataset().metaData;
var yScale = this.getScaleForId(this.getDataset().yAxisID);
var xScale = this.getScaleForId(this.getDataset().xAxisID);
var scaleBase;
if (yScale.min < 0 && yScale.max < 0) {
scaleBase = yScale.getPixelForValue(yScale.max);
} else if (yScale.min > 0 && yScale.max > 0) {
scaleBase = yScale.getPixelForValue(yScale.min);
} else {
scaleBase = yScale.getPixelForValue(0);
}
// Update Points
helpers.each(points, function(point, index) {
this.updateElement(point, index, reset);
}, this);
},
updateElement: function(point, index, reset) {
var yScale = this.getScaleForId(this.getDataset().yAxisID);
var xScale = this.getScaleForId(this.getDataset().xAxisID);
var scaleBase;
if (yScale.min < 0 && yScale.max < 0) {
scaleBase = yScale.getPixelForValue(yScale.max);
} else if (yScale.min > 0 && yScale.max > 0) {
scaleBase = yScale.getPixelForValue(yScale.min);
} else {
scaleBase = yScale.getPixelForValue(0);
}
helpers.extend(point, {
// Utility
_chart: this.chart.chart,
_xScale: xScale,
_yScale: yScale,
_datasetIndex: this.index,
_index: index,
// Desired view properties
_model: {
x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo),
y: reset ? scaleBase : yScale.getPixelForValue(this.getDataset().data[index], index, this.index),
// Appearance
radius: reset ? 0 : point.custom && point.custom.radius ? point.custom.radius : this.getRadius(this.getDataset().data[index]),
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.point.backgroundColor),
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.point.borderColor),
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.point.borderWidth),
// Tooltip
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
},
});
point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
point.pivot();
},
getRadius: function(value) {
return value.r || this.chart.options.elements.point.radius;
},
draw: function(ease) {
var easingDecimal = ease || 1;
// Transition and Draw the Points
helpers.each(this.getDataset().metaData, function(point, index) {
point.transition(easingDecimal);
point.draw();
}, this);
},
setHoverStyle: function(point) {
// Point
var dataset = this.chart.data.datasets[point._datasetIndex];
var index = point._index;
point._model.radius = point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, this.chart.options.elements.point.hoverRadius)) + this.getRadius(this.getDataset().data[point._index]);
point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString());
point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, point._model.borderWidth);
},
removeHoverStyle: function(point) {
var dataset = this.chart.data.datasets[point._datasetIndex];
var index = point._index;
point._model.radius = point.custom && point.custom.radius ? point.custom.radius : this.getRadius(this.getDataset().data[point._index]);
point._model.backgroundColor = point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.point.backgroundColor);
point._model.borderColor = point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.point.borderColor);
point._model.borderWidth = point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.point.borderWidth);
}
});
}).call(this);
+20 -3
Ver Arquivo
@@ -92,7 +92,7 @@
// Make sure that we handle number of datapoints changing
if (numData < numArcs) {
// Remove excess bars for data points that have been removed
this.getDataset().metaData.splice(numData, numArcs - numData)
this.getDataset().metaData.splice(numData, numArcs - numData);
} else if (numData > numArcs) {
// Add new elements
for (var index = numArcs; index < numData; ++index) {
@@ -101,18 +101,35 @@
}
},
getVisibleDatasetCount: function getVisibleDatasetCount() {
return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
},
// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
getRingIndex: function getRingIndex(datasetIndex) {
var ringIndex = 0;
for (var j = 0; j < datasetIndex; ++j) {
if (helpers.isDatasetVisible(this.chart.data.datasets[j])) {
++ringIndex;
}
}
return ringIndex;
},
update: function update(reset) {
this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) / 2) - this.chart.options.elements.arc.borderWidth / 2, 0);
this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length;
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
this.getDataset().total = 0;
helpers.each(this.getDataset().data, function(value) {
this.getDataset().total += Math.abs(value);
}, this);
this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.index);
this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.getRingIndex(this.index));
this.innerRadius = this.outerRadius - this.chart.radiusLength;
helpers.each(this.getDataset().metaData, function(arc, index) {
+2 -4
Ver Arquivo
@@ -153,8 +153,6 @@
borderDashOffset: line.custom && line.custom.borderDashOffset ? line.custom.borderDashOffset : (this.getDataset().borderDashOffset || this.chart.options.elements.line.borderDashOffset),
borderJoinStyle: line.custom && line.custom.borderJoinStyle ? line.custom.borderJoinStyle : (this.getDataset().borderJoinStyle || this.chart.options.elements.line.borderJoinStyle),
fill: line.custom && line.custom.fill ? line.custom.fill : (this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill),
skipNull: this.getDataset().skipNull !== undefined ? this.getDataset().skipNull : this.chart.options.elements.line.skipNull,
drawNull: this.getDataset().drawNull !== undefined ? this.getDataset().drawNull : this.chart.options.elements.line.drawNull,
// Scale
scaleTop: yScale.top,
scaleBottom: yScale.bottom,
@@ -202,12 +200,12 @@
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor),
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor),
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth),
skip: point.custom && point.custom.skip ? point.custom.skip : this.getDataset().data[index] === null,
// Tooltip
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
},
});
point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
},
updateBezierControlPoints: function() {
+6 -10
Ver Arquivo
@@ -87,7 +87,7 @@
// Make sure that we handle number of datapoints changing
if (numData < numPoints) {
// Remove excess bars for data points that have been removed
this.getDataset().metaData.splice(numData, numPoints - numData)
this.getDataset().metaData.splice(numData, numPoints - numData);
} else if (numData > numPoints) {
// Add new elements
for (var index = numPoints; index < numData; ++index) {
@@ -96,10 +96,14 @@
}
},
getVisibleDatasetCount: function getVisibleDatasetCount() {
return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
},
update: function update(reset) {
this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) - this.chart.options.elements.arc.borderWidth / 2) / 2, 0);
this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length;
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
this.getDataset().total = 0;
helpers.each(this.getDataset().data, function(value) {
@@ -202,12 +206,4 @@
},
});
return;
Chart.Type.extend({});
}).call(this);
+3 -4
Ver Arquivo
@@ -103,7 +103,7 @@
// Make sure that we handle number of datapoints changing
if (numData < numPoints) {
// Remove excess bars for data points that have been removed
this.getDataset().metaData.splice(numData, numPoints - numData)
this.getDataset().metaData.splice(numData, numPoints - numData);
} else if (numData > numPoints) {
// Add new elements
for (var index = numPoints; index < numData; ++index) {
@@ -141,8 +141,6 @@
borderWidth: this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth,
borderColor: this.getDataset().borderColor || this.chart.options.elements.line.borderColor,
fill: this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill, // use the value from the this.getDataset() if it was provided. else fall back to the default
skipNull: this.getDataset().skipNull !== undefined ? this.getDataset().skipNull : this.chart.options.elements.line.skipNull,
drawNull: this.getDataset().drawNull !== undefined ? this.getDataset().drawNull : this.chart.options.elements.line.drawNull,
// Scale
scaleTop: scale.top,
@@ -181,12 +179,13 @@
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor),
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor),
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth),
skip: point.custom && point.custom.skip ? point.custom.skip : this.getDataset().data[index] === null,
// Tooltip
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
},
});
point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
},
updateBezierControlPoints: function() {
helpers.each(this.getDataset().metaData, function(point, index) {
+63 -31
Ver Arquivo
@@ -4,7 +4,7 @@
//Declare root variable - window in the browser, global on the server
var root = this,
previous = root.Chart,
Chart = root.Chart,
helpers = Chart.helpers;
@@ -158,7 +158,7 @@
this.scale = scale;
this.scales['radialScale'] = scale;
this.scales.radialScale = scale;
}
Chart.scaleService.update(this, this.chart.width, this.chart.height);
@@ -260,7 +260,9 @@
// Draw each dataset via its respective controller (reversed to support proper line stacking)
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
dataset.controller.draw(ease);
if (helpers.isDatasetVisible(dataset)) {
dataset.controller.draw(ease);
}
}, this);
// Finally draw the tooltip
@@ -275,12 +277,14 @@
var elementsArray = [];
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
helpers.each(dataset.metaData, function(element, index) {
if (element.inRange(eventPosition.x, eventPosition.y)) {
elementsArray.push(element);
return elementsArray;
}
}, this);
if (helpers.isDatasetVisible(dataset)) {
helpers.each(dataset.metaData, function(element, index) {
if (element.inRange(eventPosition.x, eventPosition.y)) {
elementsArray.push(element);
return elementsArray;
}
}, this);
}
}, this);
return elementsArray;
@@ -291,11 +295,13 @@
var elementsArray = [];
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
helpers.each(dataset.metaData, function(element, index) {
if (element.inLabelRange(eventPosition.x, eventPosition.y)) {
elementsArray.push(element);
}
}, this);
if (helpers.isDatasetVisible(dataset)) {
helpers.each(dataset.metaData, function(element, index) {
if (element.inLabelRange(eventPosition.x, eventPosition.y)) {
elementsArray.push(element);
}
}, this);
}
}, this);
return elementsArray;
@@ -305,21 +311,23 @@
var eventPosition = helpers.getRelativePosition(e, this.chart);
var elementsArray = [];
for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; datasetIndex++) {
for (var elementIndex = 0; elementIndex < this.data.datasets[datasetIndex].metaData.length; elementIndex++) {
if (this.data.datasets[datasetIndex].metaData[elementIndex].inLabelRange(eventPosition.x, eventPosition.y)) {
helpers.each(this.data.datasets[datasetIndex].metaData, function(element, index) {
elementsArray.push(element);
}, this);
}
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
if (helpers.isDatasetVisible(dataset)) {
helpers.each(dataset.metaData, function(element, elementIndex) {
if (element.inLabelRange(eventPosition.x, eventPosition.y)) {
helpers.each(dataset.metaData, function(element, index) {
elementsArray.push(element);
}, this);
}
}, this);
}
}
}, this);
return elementsArray.length ? elementsArray : [];
},
generateLegend: function generateLegend() {
return helpers.template(this.options.legendTemplate, this);
return this.options.legendCallback(this);
},
destroy: function destroy() {
@@ -363,10 +371,11 @@
},
eventHandler: function eventHandler(e) {
this.lastActive = this.lastActive || [];
this.lastTooltipActive = this.lastTooltipActive || [];
// Find Active Elements
// Find Active Elements for hover and tooltips
if (e.type == 'mouseout') {
this.active = [];
this.active = this.tooltipActive = [];
} else {
this.active = function() {
switch (this.options.hover.mode) {
@@ -380,6 +389,18 @@
return e;
}
}.call(this);
this.tooltipActive = function() {
switch (this.options.tooltips.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
@@ -395,6 +416,7 @@
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) {
@@ -420,8 +442,8 @@
break;
case 'label':
case 'dataset':
for (var i = 0; i < this.active.length; i++) {
this.data.datasets[this.active[i]._datasetIndex].controller.setHoverStyle(this.active[i]);
for (var j = 0; j < this.active.length; j++) {
this.data.datasets[this.active[j]._datasetIndex].controller.setHoverStyle(this.active[j]);
}
break;
default:
@@ -437,11 +459,11 @@
this.tooltip.initialize();
// Active
if (this.active.length) {
if (this.tooltipActive.length) {
this.tooltip._model.opacity = 1;
helpers.extend(this.tooltip, {
_active: this.active,
_active: this.tooltipActive,
});
this.tooltip.update();
@@ -463,10 +485,19 @@
}
}, this);
helpers.each(this.tooltipActive, function(element, index) {
if (element !== this.lastTooltipActive[index]) {
changed = true;
}
}, this);
// If entering, leaving, or changing elements, animate the change via pivot
if ((!this.lastActive.length && this.active.length) ||
(this.lastActive.length && !this.active.length) ||
(this.lastActive.length && this.active.length && changed)) {
(this.lastActive.length && this.active.length && changed) ||
(!this.lastTooltipActive.length && this.tooltipActive.length) ||
(this.lastTooltipActive.length && !this.tooltipActive.length) ||
(this.lastTooltipActive.length && this.tooltipActive.length && changed)) {
this.stop();
@@ -476,8 +507,9 @@
}
}
// Remember Last Active
// Remember Last Actives
this.lastActive = this.active;
this.lastTooltipActive = this.tooltipActive;
return this;
},
});
+1 -1
Ver Arquivo
@@ -4,7 +4,7 @@
//Declare root variable - window in the browser, global on the server
var root = this,
previous = root.Chart,
Chart = root.Chart,
helpers = Chart.helpers;
Chart.elements = {};
+29 -64
Ver Arquivo
@@ -4,7 +4,7 @@
//Declare root variable - window in the browser, global on the server
var root = this,
previous = root.Chart;
Chart = root.Chart;
//Global Chart helpers object for utility methods and classes
var helpers = Chart.helpers = {};
@@ -135,7 +135,7 @@
base[key].push(helpers.configMerge(valueObj.type ? Chart.scaleService.getScaleDefaults(valueObj.type) : {}, valueObj));
} else if (valueObj.type !== base[key][index].type) {
// Type changed. Bring in the new defaults before we bring in valueObj so that valueObj can override the correct scale defaults
base[key][index] = helpers.configMerge(base[key][index], valueObj.type ? Chart.scaleService.getScaleDefaults(valueObj.type) : {}, valueObj)
base[key][index] = helpers.configMerge(base[key][index], valueObj.type ? Chart.scaleService.getScaleDefaults(valueObj.type) : {}, valueObj);
} else {
// Type is the same
base[key][index] = helpers.configMerge(base[key][index], valueObj);
@@ -272,7 +272,7 @@
},
log10 = helpers.log10 = function(x) {
if (Math.log10) {
return Math.log10(x)
return Math.log10(x);
} else {
return Math.log(x) / Math.LN10;
}
@@ -324,18 +324,32 @@
splineCurve = helpers.splineCurve = function(FirstPoint, MiddlePoint, AfterPoint, t) {
//Props to Rob Spencer at scaled innovation for his post on splining between points
//http://scaledinnovation.com/analytics/splines/aboutSplines.html
var d01 = Math.sqrt(Math.pow(MiddlePoint.x - FirstPoint.x, 2) + Math.pow(MiddlePoint.y - FirstPoint.y, 2)),
d12 = Math.sqrt(Math.pow(AfterPoint.x - MiddlePoint.x, 2) + Math.pow(AfterPoint.y - MiddlePoint.y, 2)),
// This function must also respect "skipped" points
var previous = FirstPoint,
current = MiddlePoint,
next = AfterPoint;
if (previous.skip) {
previous = current;
}
if (next.skip) {
next = current;
}
var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2)),
d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2)),
fa = t * d01 / (d01 + d12), // scaling factor for triangle Ta
fb = t * d12 / (d01 + d12);
return {
previous: {
x: MiddlePoint.x - fa * (AfterPoint.x - FirstPoint.x),
y: MiddlePoint.y - fa * (AfterPoint.y - FirstPoint.y)
x: current.x - fa * (next.x - previous.x),
y: current.y - fa * (next.y - previous.y)
},
next: {
x: MiddlePoint.x + fb * (AfterPoint.x - FirstPoint.x),
y: MiddlePoint.y + fb * (AfterPoint.y - FirstPoint.y)
x: current.x + fb * (next.x - previous.x),
y: current.y + fb * (next.y - previous.y)
}
};
},
@@ -382,57 +396,6 @@
return niceFraction * Math.pow(10, exponent);
},
/* jshint ignore:start */
// Blows up jshint errors based on the new Function constructor
//Templating methods
//Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/
templateStringCache = {},
template = helpers.template = function(templateString, valuesObject) {
// If templateString is function rather than string-template - call the function for valuesObject
if (templateString instanceof Function) {
return templateString(valuesObject);
}
function tmpl(str, data) {
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn;
if (templateStringCache.hasOwnProperty(str)) {
fn = templateStringCache[str];
} else {
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
var functionCode = "var p=[],print=function(){p.push.apply(p,arguments);};" +
// Introduce the data as local variables using with(){}
"with(obj){p.push('" +
// Convert the template into pure JavaScript
str
.replace(/[\r\t\n]/g, " ")
.split("<%").join("\t")
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%>/g, "',$1,'")
.split("\t").join("');")
.split("%>").join("p.push('")
.split("\r").join("\\'") +
"');}return p.join('');";
fn = new Function("obj", functionCode);
// Cache the result
templateStringCache[str] = fn;
}
// Provide some basic currying to the user
return data ? fn(data) : fn;
}
return tmpl(templateString, valuesObject);
},
/* jshint ignore:end */
//--Animation methods
//Easing functions adapted from Robert Penner's easing equations
//http://www.robertpenner.com/easing/
easingEffects = helpers.easingEffects = {
@@ -837,7 +800,7 @@
// can use classlist
hiddenIframe.classlist.add(hiddenIframeClass);
} else {
hiddenIframe.setAttribute('class', hiddenIframeClass)
hiddenIframe.setAttribute('class', hiddenIframeClass);
}
// Set the style
@@ -860,14 +823,14 @@
if (callback) {
callback();
}
}
};
},
removeResizeListener = helpers.removeResizeListener = function(node) {
var hiddenIframe = node.querySelector('.chartjs-hidden-iframe');
// Remove the resize detect iframe
if (hiddenIframe) {
hiddenIframe.remove();
hiddenIframe.parentNode.removeChild(hiddenIframe);
}
},
isArray = helpers.isArray = function(obj) {
@@ -875,6 +838,8 @@
return Object.prototype.toString.call(arg) === '[object Array]';
}
return Array.isArray(obj);
},
isDatasetVisible = helpers.isDatasetVisible = function(dataset) {
return !dataset.hidden;
};
}).call(this);
+21 -9
Ver Arquivo
@@ -57,20 +57,19 @@
// High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
Chart.helpers.retinaScale(this);
if (config) {
this.controller = new Chart.Controller(this);
}
// Always bind this so that if the responsive state changes we still work
var _this = this;
Chart.helpers.addResizeListener(context.canvas.parentNode, function() {
if (config.options.responsive) {
if (_this.controller && _this.controller.config.options.responsive) {
_this.controller.resize();
}
});
if (config) {
this.controller = new Chart.Controller(this);
return this.controller;
}
return this;
return this.controller ? this.controller : this;
};
@@ -92,8 +91,21 @@
// Element defaults defined in element extensions
elements: {},
// Legend template string
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i = 0; i < data.datasets.length; i++){%><li><span style=\"background-color:<%=data.datasets[i].backgroundColor%>\"><%if(data.datasets[i].label){%><%=data.datasets[i].label%><%}%></span></li><%}%></ul>",
// Legend callback string
legendCallback: function(chart) {
var text = [];
text.push('<ul class="' + chart.id + '-legend">');
for (var i = 0; i < chart.data.datasets.length; i++) {
text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '">');
if (chart.data.datasets[i].label) {
text.push(chart.data.datasets[i].label);
}
text.push('</span></li>');
}
text.push('</ul>');
return text.join("");
}
},
};
+54 -21
Ver Arquivo
@@ -47,7 +47,9 @@
padding: 10,
reverse: false,
show: true,
template: "<%=value%>",
callback: function(value) {
return '' + value;
},
},
};
@@ -103,9 +105,16 @@
setDimensions: function() {
// Set the unconstrained dimension before label rotation
if (this.isHorizontal()) {
// Reset position before calculating rotation
this.width = this.maxWidth;
this.left = 0;
this.right = this.width;
} else {
this.height = this.maxHeight;
// Reset position before calculating rotation
this.top = 0;
this.bottom = this.height;
}
// Reset padding
@@ -126,14 +135,12 @@
convertTicksToLabels: function() {
// Convert ticks to strings
this.ticks = this.ticks.map(function(numericalTick, index, ticks) {
if (this.options.ticks.userCallback) {
return this.options.ticks.userCallback(numericalTick, index, ticks);
} else {
return helpers.template(this.options.ticks.template, {
value: numericalTick
});
}
}, this);
if (this.options.ticks.userCallback) {
return this.options.ticks.userCallback(numericalTick, index, ticks);
}
return this.options.ticks.callback(numericalTick, index, ticks);
},
this);
},
afterTickToLabelConversion: helpers.noop,
@@ -235,13 +242,13 @@
}
// Are we showing a title for the scale?
if (this.options.scaleLabel.show) {
if (this.isHorizontal()) {
this.minSize.height += (this.options.scaleLabel.fontSize * 1.5);
} else {
this.minSize.width += (this.options.scaleLabel.fontSize * 1.5);
}
}
if (this.options.scaleLabel.show) {
if (this.isHorizontal()) {
this.minSize.height += (this.options.scaleLabel.fontSize * 1.5);
} else {
this.minSize.width += (this.options.scaleLabel.fontSize * 1.5);
}
}
if (this.options.ticks.show && this.options.display) {
// Don't bother fitting the ticks if we are not showing them
@@ -309,6 +316,29 @@
return this.options.position == "top" || this.options.position == "bottom";
},
// Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
getRightValue: function getRightValue(rawValue) {
// Null and undefined values first
if (rawValue === null || typeof(rawValue) === 'undefined') {
return NaN;
}
// isNaN(object) returns true, so make sure NaN is checking for a number
if (typeof(rawValue) === 'number' && isNaN(rawValue)) {
return NaN;
}
// If it is in fact an object, dive in one more level
if (typeof(rawValue) === "object") {
return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
}
// Value is good, return it
return rawValue;
},
// Used to get the value to display in the tooltip for the data at the given index
// function getLabelForIndex(index, datasetIndex)
getLabelForIndex: helpers.noop,
// Used to get data value locations. Value can either be an index or a numerical value
getPixelForValue: helpers.noop,
@@ -337,7 +367,7 @@
return this.left + Math.round(valueOffset);
} else {
return this.top + (decimal * (this.height / this.ticks.length));
return this.top + (decimal * this.height);
}
},
@@ -352,8 +382,9 @@
var scaleLabelX;
var scaleLabelY;
// Make sure we draw text in the correct color
// Make sure we draw text in the correct color and font
this.ctx.fillStyle = this.options.ticks.fontColor;
var labelFont = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
if (this.isHorizontal()) {
setContextLineSettings = true;
@@ -409,7 +440,7 @@
this.ctx.save();
this.ctx.translate(xLabelValue, (isRotated) ? this.top + 12 : this.options.position === "top" ? this.bottom - 10 : this.top + 10);
this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1);
this.ctx.font = this.font;
this.ctx.font = labelFont;
this.ctx.textAlign = (isRotated) ? "right" : "center";
this.ctx.textBaseline = (isRotated) ? "middle" : this.options.position === "top" ? "bottom" : "top";
this.ctx.fillText(label, 0, 0);
@@ -421,6 +452,7 @@
// Draw the scale label
this.ctx.textAlign = "center";
this.ctx.textBaseline = 'middle';
this.ctx.fillStyle = this.options.scaleLabel.fontColor; // render in correct colour
this.ctx.font = helpers.fontString(this.options.scaleLabel.fontSize, this.options.scaleLabel.fontStyle, this.options.scaleLabel.fontFamily);
scaleLabelX = this.left + ((this.right - this.left) / 2); // midpoint of the width
@@ -494,10 +526,10 @@
}
}
this.ctx.translate(xLabelValue, yLabelValue);
this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1);
this.ctx.font = this.font;
this.ctx.font = labelFont;
this.ctx.textBaseline = "middle";
this.ctx.fillText(label, 0, 0);
this.ctx.restore();
@@ -514,6 +546,7 @@
this.ctx.translate(scaleLabelX, scaleLabelY);
this.ctx.rotate(rotation);
this.ctx.textAlign = "center";
this.ctx.fillStyle = this.options.scaleLabel.fontColor; // render in correct colour
this.ctx.font = helpers.fontString(this.options.scaleLabel.fontSize, this.options.scaleLabel.fontStyle, this.options.scaleLabel.fontFamily);
this.ctx.textBaseline = 'middle';
this.ctx.fillText(this.options.scaleLabel.labelString, 0, 0);
+3 -2
Ver Arquivo
@@ -19,13 +19,14 @@
defaults: {},
registerScaleType: function(type, scaleConstructor, defaults) {
this.constructors[type] = scaleConstructor;
this.defaults[type] = helpers.scaleMerge(Chart.defaults.scale, defaults);
this.defaults[type] = helpers.clone(defaults);
},
getScaleConstructor: function(type) {
return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
},
getScaleDefaults: function(type) {
return this.defaults.hasOwnProperty(type) ? this.defaults[type] : {};
// Return the scale defaults merged with the global settings so that we always use the latest ones
return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
},
// The interesting function
update: function(chartInstance, width, height) {
+390 -269
Ver Arquivo
@@ -9,35 +9,71 @@
Chart.defaults.global.tooltips = {
enabled: true,
custom: null,
mode: 'single',
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",
titleSpacing: 2,
titleMarginBottom: 6,
titleColor: "#fff",
titleAlign: "left",
bodyFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
bodyFontSize: 12,
bodyFontStyle: "normal",
bodySpacing: 2,
bodyColor: "#fff",
bodyAlign: "left",
footerFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
footerFontSize: 12,
footerFontStyle: "bold",
footerSpacing: 2,
footerMarginTop: 6,
footerColor: "#fff",
footerAlign: "left",
yPadding: 6,
xPadding: 6,
caretSize: 8,
caretSize: 5,
cornerRadius: 6,
xOffset: 10,
template: [
'<% if(label){ %>',
'<%=label %>: ',
'<% } %>',
'<%=value %>',
].join(''),
multiTemplate: [
'<%if (datasetLabel){ %>',
'<%=datasetLabel %>: ',
'<% } %>',
'<%=value %>'
].join(''),
multiKeyBackground: '#fff',
callbacks: {
beforeTitle: helpers.noop,
title: function(xLabel, yLabel, index, datasetIndex, data) {
// Pick first label for now
return helpers.isArray(xLabel) ? xLabel[0] : xLabel;
},
afterTitle: helpers.noop,
beforeBody: helpers.noop,
beforeLabel: helpers.noop,
label: function(xLabel, yLabel, index, datasetIndex, data) {
return this._data.datasets[datasetIndex].label + ': ' + yLabel;
},
afterLabel: helpers.noop,
afterBody: helpers.noop,
beforeFooter: helpers.noop,
footer: helpers.noop,
afterFooter: helpers.noop,
},
};
// Helper to push or concat based on if the 2nd parameter is an array or not
function pushOrConcat(base, toPush) {
if (toPush) {
if (helpers.isArray(toPush)) {
base = base.concat(toPush);
} else {
base.push(toPush);
}
}
return base;
}
Chart.Tooltip = Chart.Element.extend({
initialize: function() {
var options = this._options;
@@ -48,20 +84,34 @@
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,
// Body
bodyColor: options.tooltips.bodyColor,
_bodyFontFamily: options.tooltips.bodyFontFamily,
_bodyFontStyle: options.tooltips.bodyFontStyle,
bodyFontSize: options.tooltips.bodyFontSize,
bodySpacing: options.tooltips.bodySpacing,
_bodposition: options.tooltips.bodposition,
// Title
titleTextColor: options.tooltips.titleFontColor,
titleColor: options.tooltips.titleColor,
_titleFontFamily: options.tooltips.titleFontFamily,
_titleFontStyle: options.tooltips.titleFontStyle,
titleFontSize: options.tooltips.titleFontSize,
_titleAlign: options.tooltips.titleAlign,
titleSpacing: options.tooltips.titleSpacing,
titleMarginBottom: options.tooltips.titleMarginBottom,
// Footer
footerColor: options.tooltips.footerColor,
_footerFontFamily: options.tooltips.footerFontFamily,
_footerFontStyle: options.tooltips.footerFontStyle,
footerFontSize: options.tooltips.footerFontSize,
_footerAlign: options.tooltips.footerAlign,
footerSpacing: options.tooltips.footerSpacing,
footerMarginTop: options.tooltips.footerMarginTop,
// Appearance
caretHeight: options.tooltips.caretSize,
caretSize: options.tooltips.caretSize,
cornerRadius: options.tooltips.cornerRadius,
backgroundColor: options.tooltips.backgroundColor,
opacity: 0,
@@ -69,141 +119,145 @@
},
});
},
// Get the title
getTitle: function() {
var beforeTitle = this._options.tooltips.callbacks.beforeTitle.apply(this, arguments),
title = this._options.tooltips.callbacks.title.apply(this, arguments),
afterTitle = this._options.tooltips.callbacks.afterTitle.apply(this, arguments);
var lines = [];
lines = pushOrConcat(lines, beforeTitle);
lines = pushOrConcat(lines, title);
lines = pushOrConcat(lines, afterTitle);
return lines;
},
getBeforeBody: function(xLabel, yLabel, index, datasetIndex, data) {
var lines = this._options.tooltips.callbacks.beforeBody.call(this, xLabel, yLabel, index, datasetIndex, data);
return helpers.isArray(lines) ? lines : [lines];
},
getBody: function(xLabel, yLabel, index, datasetIndex) {
var lines = [];
var beforeLabel,
afterLabel,
label;
if (helpers.isArray(xLabel)) {
var labels = [];
// Run EACH label pair through the label callback this time.
for (var i = 0; i < xLabel.length; i++) {
beforeLabel = this._options.tooltips.callbacks.beforeLabel.call(this, xLabel[i], yLabel[i], index, datasetIndex);
afterLabel = this._options.tooltips.callbacks.afterLabel.call(this, xLabel[i], yLabel[i], index, datasetIndex);
labels.push((beforeLabel ? beforeLabel : '') + this._options.tooltips.callbacks.label.call(this, xLabel[i], yLabel[i], index, datasetIndex) + (afterLabel ? afterLabel : ''));
}
if (labels.length) {
lines = lines.concat(labels);
}
} else {
// Run the single label through the callback
beforeLabel = this._options.tooltips.callbacks.beforeLabel.apply(this, arguments);
label = this._options.tooltips.callbacks.label.apply(this, arguments);
afterLabel = this._options.tooltips.callbacks.afterLabel.apply(this, arguments);
if (beforeLabel || label || afterLabel) {
lines.push((beforeLabel ? afterLabel : '') + label + (afterLabel ? afterLabel : ''));
}
}
return lines;
},
getAfterBody: function(xLabel, yLabel, index, datasetIndex, data) {
var lines = this._options.tooltips.callbacks.afterBody.call(this, xLabel, yLabel, index, datasetIndex, data);
return helpers.isArray(lines) ? lines : [lines];
},
// Get the footer and beforeFooter and afterFooter lines
getFooter: function() {
var beforeFooter = this._options.tooltips.callbacks.beforeFooter.apply(this, arguments);
var footer = this._options.tooltips.callbacks.footer.apply(this, arguments);
var afterFooter = this._options.tooltips.callbacks.afterFooter.apply(this, arguments);
var lines = [];
lines = pushOrConcat(lines, beforeFooter);
lines = pushOrConcat(lines, footer);
lines = pushOrConcat(lines, afterFooter);
return lines;
},
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._active[0]._model.label !== undefined ? this._active[0]._model.label : this._data.labels ? this._data.labels[this._active[0]._index] : '',
}),
});
var element = this._active[0],
xLabel,
yLabel,
labelColors = [],
tooltipPosition;
var tooltipPosition = this._active[0].tooltipPosition();
helpers.extend(this._model, {
x: Math.round(tooltipPosition.x),
y: Math.round(tooltipPosition.y),
caretPadding: tooltipPosition.padding
});
if (this._options.tooltips.mode == 'single') {
break;
xLabel = element._xScale.getLabelForIndex(element._index, element._datasetIndex);
yLabel = element._yScale.getLabelForIndex(element._index, element._datasetIndex);
tooltipPosition = this._active[0].tooltipPosition();
case 'label':
} else {
// Tooltip Content
xLabel = [];
yLabel = [];
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;
}
helpers.each(this._data.datasets, function(dataset, datasetIndex) {
if (!helpers.isDatasetVisible(dataset)) {
return;
}
xLabel.push(element._xScale.getLabelForIndex(element._index, datasetIndex));
yLabel.push(element._yScale.getLabelForIndex(element._index, datasetIndex));
});
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: (function() {
return this._data.timeLabels ? this._data.timeLabels[this._active[0]._index] :
(this._data.labels && this._data.labels.length) ? this._data.labels[this._active[0]._index] :
'';
}).call(this),
legendColors: colors,
legendBackgroundColor: this._options.tooltips.multiKeyBackground,
helpers.each(this._active, function(active, i) {
labelColors.push({
borderColor: active._view.borderColor,
backgroundColor: active._view.backgroundColor
});
}, this);
tooltipPosition = this._active[0].tooltipPosition();
tooltipPosition.y = this._active[0]._yScale.getPixelForDecimal(0.5);
// 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._model.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;
}
// Build the Text Lines
helpers.extend(this._model, {
title: this.getTitle(xLabel, yLabel, element._index, element._datasetIndex, this._data),
beforeBody: this.getBeforeBody(xLabel, yLabel, element._index, element._datasetIndex, this._data),
body: this.getBody(xLabel, yLabel, element._index, element._datasetIndex, this._data),
afterBody: this.getAfterBody(xLabel, yLabel, element._index, element._datasetIndex, this._data),
footer: this.getFooter(xLabel, yLabel, element._index, element._datasetIndex, this._data),
});
helpers.extend(this._model, {
x: Math.round(tooltipPosition.x),
y: Math.round(tooltipPosition.y),
caretPadding: tooltipPosition.padding,
labelColors: labelColors,
});
return this;
},
draw: function() {
@@ -211,136 +265,203 @@
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._options.tooltips.custom) {
this._options.tooltips.custom(this);
}
if (!this._options.tooltips.enabled) {
return;
}
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':
// Custom Tooltips
if (this._options.tooltips.custom) {
this._options.tooltips.custom(this);
}
if (!this._options.tooltips.enabled) {
return;
}
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;
if (this._view.opacity === 0) {
return;
}
},
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;
// Get Dimensions
vm.position = "top";
var caretPadding = vm.caretPadding || 2;
var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length;
// Height
var tooltipHeight = vm.yPadding * 2; // Tooltip Padding
tooltipHeight += vm.title.length * vm.titleFontSize; // Title Lines
tooltipHeight += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing
tooltipHeight += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin
tooltipHeight += combinedBodyLength * vm.bodyFontSize; // Body Lines
tooltipHeight += (combinedBodyLength - 1) * vm.bodySpacing; // Body Line Spacing
tooltipHeight += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin
tooltipHeight += vm.footer.length * (vm.footerFontSize); // Footer Lines
tooltipHeight += (vm.footer.length - 1) * vm.footerSpacing; // Footer Line Spacing
// Width
var tooltipWidth = 0;
helpers.each(vm.title, function(line, i) {
ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
});
helpers.each(vm.body, function(line, i) {
ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width + (this._options.tooltips.mode != 'single' ? (vm.bodyFontSize + 2) : 0));
}, this);
helpers.each(vm.footer, function(line, i) {
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
});
tooltipWidth += 2 * vm.xPadding;
var tooltipTotalWidth = tooltipWidth + vm.caretSize + caretPadding;
// Smart Tooltip placement to stay on the canvas
// Top, center, or bottom
vm.yAlign = "center";
if (vm.y - (tooltipHeight / 2) < 0) {
vm.yAlign = "top";
} else if (vm.y + (tooltipHeight / 2) > this._chart.height) {
vm.yAlign = "bottom";
}
// Left or Right
vm.xAlign = "right";
if (vm.x + tooltipTotalWidth > this._chart.width) {
vm.xAlign = "left";
}
// Background Position
var tooltipX = vm.x,
tooltipY = vm.y;
if (vm.yAlign == 'top') {
tooltipY = vm.y - vm.caretSize - vm.cornerRadius;
} else if (vm.yAlign == 'bottom') {
tooltipY = vm.y - tooltipHeight + vm.caretSize + vm.cornerRadius;
} else {
return baseLineHeight + ((this._view.fontSize * 1.5 * afterTitleIndex) + this._view.fontSize / 2) + this._view.titleFontSize * 1.5;
tooltipY = vm.y - (tooltipHeight / 2);
}
if (vm.xAlign == 'left') {
tooltipX = vm.x - tooltipTotalWidth;
} else if (vm.xAlign == 'right') {
tooltipX = vm.x + caretPadding + vm.caretSize;
} else {
tooltipX = vm.x + (tooltipTotalWidth / 2);
}
// Draw Background
if (this._options.tooltips.enabled) {
ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(vm.opacity).rgbString();
helpers.drawRoundedRectangle(ctx, tooltipX, tooltipY, tooltipWidth, tooltipHeight, vm.cornerRadius);
ctx.fill();
}
// Draw Caret
if (this._options.tooltips.enabled) {
ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(vm.opacity).rgbString();
if (vm.xAlign == 'left') {
ctx.beginPath();
ctx.moveTo(vm.x - caretPadding, vm.y);
ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y - vm.caretSize);
ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y + vm.caretSize);
ctx.closePath();
ctx.fill();
} else {
ctx.beginPath();
ctx.moveTo(vm.x + caretPadding, vm.y);
ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y - vm.caretSize);
ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y + vm.caretSize);
ctx.closePath();
ctx.fill();
}
}
// Draw Title, Body, and Footer
if (this._options.tooltips.enabled) {
var yBase = tooltipY + vm.yPadding;
var xBase = tooltipX + vm.xPadding;
// Titles
if (vm.title.length) {
ctx.textAlign = vm._titleAlign;
ctx.textBaseline = "top";
ctx.fillStyle = helpers.color(vm.titleColor).alpha(vm.opacity).rgbString();
ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
helpers.each(vm.title, function(title, i) {
ctx.fillText(title, xBase, yBase);
yBase += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing
if (i + 1 == vm.title.length) {
yBase += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing
}
}, this);
}
// Body
ctx.textAlign = vm._bodyAlign;
ctx.textBaseline = "top";
ctx.fillStyle = helpers.color(vm.bodyColor).alpha(vm.opacity).rgbString();
ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
// Before Body
helpers.each(vm.beforeBody, function(beforeBody, i) {
ctx.fillText(vm.beforeBody, xBase, yBase);
yBase += vm.bodyFontSize + vm.bodySpacing;
});
helpers.each(vm.body, function(body, i) {
// Draw Legend-like boxes if needed
if (this._options.tooltips.mode != 'single') {
ctx.fillStyle = helpers.color(vm.labelColors[i].borderColor).alpha(vm.opacity).rgbString();
ctx.fillRect(xBase, yBase, vm.bodyFontSize, vm.bodyFontSize);
ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(vm.opacity).rgbString();
ctx.fillRect(xBase + 1, yBase + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
ctx.fillStyle = helpers.color(vm.bodyColor).alpha(vm.opacity).rgbString(); // Return fill style for text
}
// Body Line
ctx.fillText(body, xBase + (this._options.tooltips.mode != 'single' ? (vm.bodyFontSize + 2) : 0), yBase);
yBase += vm.bodyFontSize + vm.bodySpacing;
}, this);
// After Body
helpers.each(vm.afterBody, function(afterBody, i) {
ctx.fillText(vm.afterBody, xBase, yBase);
yBase += vm.bodyFontSize;
});
yBase -= vm.bodySpacing; // Remove last body spacing
// Footer
if (vm.footer.length) {
yBase += vm.footerMarginTop;
ctx.textAlign = vm._footerAlign;
ctx.textBaseline = "top";
ctx.fillStyle = helpers.color(vm.footerColor).alpha(vm.opacity).rgbString();
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
helpers.each(vm.footer, function(footer, i) {
ctx.fillText(footer, xBase, yBase);
yBase += vm.footerFontSize + vm.footerSpacing;
}, this);
}
}
},
});
+1 -1
Ver Arquivo
@@ -45,7 +45,7 @@
// 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
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),
+59 -60
Ver Arquivo
@@ -27,8 +27,6 @@
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
fill: true, // do we fill in the area between the line and its base axis
skipNull: true,
drawNull: false,
};
@@ -44,50 +42,51 @@
// Draw the background first (so the border is always on top)
helpers.each(this._children, function(point, index) {
var previous = helpers.previousItem(this._children, index);
var next = helpers.nextItem(this._children, index);
// First point only
if (index === 0) {
ctx.moveTo(point._view.x, point._view.y);
// First point moves to it's starting position no matter what
if (!index) {
ctx.moveTo(point._view.x, vm.scaleZero);
}
// Skip this point, draw to scaleZero, move to next point, and draw to next point
if (point._view.skip && !this.loop) {
ctx.lineTo(previous._view.x, vm.scaleZero);
ctx.moveTo(next._view.x, vm.scaleZero);
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);
// The previous line was skipped, so just draw a normal straight line to the point
if (previous._view.skip) {
ctx.lineTo(point._view.x, point._view.y);
return;
}
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);
}
// Draw a bezier to point
if (vm.tension > 0 && index) {
//ctx.lineTo(point._view.x, point._view.y);
ctx.bezierCurveTo(
previous._view.controlPointNextX,
previous._view.controlPointNextY,
point._view.controlPointPreviousX,
point._view.controlPointPreviousY,
point._view.x,
point._view.y
);
return;
}
// Draw a straight line to the point
ctx.lineTo(point._view.x, point._view.y);
}, this);
// For radial scales, loop back around to the first point
if (this._loop) {
// Draw a bezier line
if (vm.tension > 0 && !first._view.skip) {
ctx.bezierCurveTo(
last._view.controlPointNextX,
last._view.controlPointNextY,
@@ -96,9 +95,10 @@
first._view.x,
first._view.y
);
} else {
ctx.lineTo(first._view.x, first._view.y);
return;
}
// Draw a straight line
ctx.lineTo(first._view.x, first._view.y);
}
// If we had points and want to fill this line, do so.
@@ -130,31 +130,24 @@
var previous = helpers.previousItem(this._children, index);
var next = helpers.nextItem(this._children, index);
// First point only
if (index === 0) {
if (!index) {
ctx.moveTo(point._view.x, vm.scaleZero);
}
// Skip this point and move to the next points zeroPoint
if (point._view.skip && !this.loop) {
ctx.moveTo(next._view.x, vm.scaleZero);
return;
}
// Previous point was skipped, just move to the point
if (previous._view.skip) {
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) {
// Draw a bezier line to the point
if (vm.tension > 0 && index) {
ctx.bezierCurveTo(
previous._view.controlPointNextX,
previous._view.controlPointNextY,
@@ -163,14 +156,18 @@
point._view.x,
point._view.y
);
} else {
ctx.lineTo(point._view.x, point._view.y);
return;
}
// Draw a straight line to the point
ctx.lineTo(point._view.x, point._view.y);
}, this);
if (this._loop && !first._view.skip) {
if (vm.tension > 0) {
// Draw a bezier line to the first point
if (vm.tension > 0) {
ctx.bezierCurveTo(
last._view.controlPointNextX,
last._view.controlPointNextY,
@@ -179,9 +176,11 @@
first._view.x,
first._view.y
);
} else {
ctx.lineTo(first._view.x, first._view.y);
return;
}
// Draw a straight line to the first point
ctx.lineTo(first._view.x, first._view.y);
}
ctx.stroke();
@@ -189,4 +188,4 @@
},
});
}).call(this);
}).call(this);
+10 -7
Ver Arquivo
@@ -15,29 +15,32 @@
this.ticks = this.data.labels;
},
getLabelForIndex: function(index, datasetIndex) {
return this.ticks[index];
},
// Used to get data value locations. Value can either be an index or a numerical value
getPixelForValue: function(value, index, datasetIndex, includeOffset) {
if (this.isHorizontal()) {
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
var valueWidth = innerWidth / Math.max((this.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
var valueOffset = (valueWidth * index) + this.paddingLeft;
var widthOffset = (valueWidth * index) + this.paddingLeft;
if (this.options.gridLines.offsetGridLines && includeOffset) {
valueOffset += (valueWidth / 2);
widthOffset += (valueWidth / 2);
}
return this.left + Math.round(valueOffset);
return this.left + Math.round(widthOffset);
} else {
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
var valueHeight = innerHeight / Math.max((this.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
var valueOffset = (valueHeight * index) + this.paddingTop;
var heightOffset = (valueHeight * index) + this.paddingTop;
if (this.options.gridLines.offsetGridLines && includeOffset) {
valueOffset += (valueHeight / 2);
heightOffset += (valueHeight / 2);
}
return this.top + Math.round(valueOffset);
return this.top + Math.round(heightOffset);
}
},
});
+45 -12
Ver Arquivo
@@ -7,6 +7,32 @@
var defaultConfig = {
position: "left",
ticks: {
callback: function(tickValue, index, ticks) {
var delta = ticks[1] - ticks[0];
// If we have a number like 2.5 as the delta, figure out how many decimal places we need
if (Math.abs(delta) > 1) {
if (tickValue !== Math.floor(tickValue)) {
// not an integer
delta = tickValue - Math.floor(tickValue);
}
}
var logDelta = helpers.log10(Math.abs(delta));
var tickString = '';
if (tickValue !== 0) {
var numDecimal = -1 * Math.floor(logDelta);
numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
tickString = tickValue.toFixed(numDecimal);
} else {
tickString = '0'; // never show decimal places for 0
}
return tickString;
}
}
};
var LinearScale = Chart.Scale.extend({
@@ -21,10 +47,13 @@
if (this.options.stacked) {
helpers.each(this.data.datasets, function(dataset) {
if (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id) {
if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) {
helpers.each(dataset.data, function(rawValue, index) {
var value = this.getRightValue(rawValue);
if (isNaN(value)) {
return;
}
positiveValues[index] = positiveValues[index] || 0;
negativeValues[index] = negativeValues[index] || 0;
@@ -48,9 +77,12 @@
} else {
helpers.each(this.data.datasets, function(dataset) {
if (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id) {
if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) {
helpers.each(dataset.data, function(rawValue, index) {
var value = this.getRightValue(rawValue);
if (isNaN(value)) {
return;
}
if (this.min === null) {
this.min = value;
@@ -119,9 +151,11 @@
var niceMin = Math.floor(this.min / spacing) * spacing;
var niceMax = Math.ceil(this.max / spacing) * spacing;
var numSpaces = Math.ceil((niceMax - niceMin) / spacing);
// Put the values into the ticks array
for (var j = niceMin; j <= niceMax; j += spacing) {
this.ticks.push(j);
for (var j = 0; j <= numSpaces; ++j) {
this.ticks.push(niceMin + (j * spacing));
}
if (this.options.position == "left" || this.options.position == "right") {
@@ -147,30 +181,29 @@
this.zeroLineIndex = this.ticks.indexOf(0);
},
getLabelForIndex: function(index, datasetIndex) {
return this.getRightValue(this.data.datasets[datasetIndex].data[index]);
},
// Utils
getPixelForValue: function(value, index, datasetIndex, includeOffset) {
// This must be called after fit has been run so that
// this.left, this.top, this.right, and this.bottom have been defined
var rightValue = this.getRightValue(value);
var pixel;
var range = this.end - this.start;
if (this.isHorizontal()) {
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
pixel = this.left + (innerWidth / range * (this.getRightValue(value) - this.start));
pixel = this.left + (innerWidth / range * (rightValue - this.start));
return Math.round(pixel + this.paddingLeft);
} else {
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
pixel = (this.bottom - this.paddingBottom) - (innerHeight / range * (this.getRightValue(value) - this.start));
pixel = (this.bottom - this.paddingBottom) - (innerHeight / range * (rightValue - this.start));
return Math.round(pixel);
}
},
// 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" && rawValue !== null) ? (this.isHorizontal() ? rawValue.x : rawValue.y) : rawValue;
},
});
Chart.scaleService.registerScaleType("linear", LinearScale, defaultConfig);
+20 -6
Ver Arquivo
@@ -10,7 +10,15 @@
// label settings
ticks: {
template: "<%var remain = value / (Math.pow(10, Math.floor(Chart.helpers.log10(value))));if (remain === 1 || remain === 2 || remain === 5) {%><%=value.toExponential()%><%} else {%><%= null %><%}%>",
callback: function(value) {
var remain = value / (Math.pow(10, Math.floor(Chart.helpers.log10(value))));
if (remain === 1 || remain === 2 || remain === 5) {
return value.toExponential();
} else {
return '';
}
}
}
};
@@ -26,10 +34,13 @@
if (this.options.stacked) {
helpers.each(this.data.datasets, function(dataset) {
if (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id) {
if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) {
helpers.each(dataset.data, function(rawValue, index) {
var value = this.getRightValue(rawValue);
if (isNaN(value)) {
return;
}
values[index] = values[index] || 0;
@@ -48,9 +59,12 @@
} else {
helpers.each(this.data.datasets, function(dataset) {
if (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id) {
if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) {
helpers.each(dataset.data, function(rawValue, index) {
var value = this.getRightValue(rawValue);
if (isNaN(value)) {
return;
}
if (this.min === null) {
this.min = value;
@@ -121,9 +135,9 @@
this.ticks = this.tickValues.slice();
},
// 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;
// Get the correct tooltip label
getLabelForIndex: function(index, datasetIndex) {
return this.getRightValue(this.data.datasets[datasetIndex].data[index]);
},
getPixelForTick: function(index, includeOffset) {
return this.getPixelForValue(this.tickValues[index], null, null, includeOffset);
+22 -19
Ver Arquivo
@@ -59,7 +59,7 @@
this.height = this.maxHeight;
this.xCenter = Math.round(this.width / 2);
this.yCenter = Math.round(this.height / 2);
var minSize = helpers.min([this.height, this.width]);
this.drawingArea = (this.options.display) ? (minSize / 2) - (this.options.ticks.fontSize / 2 + this.options.ticks.backdropPaddingY) : (minSize / 2);
},
@@ -68,21 +68,26 @@
this.max = null;
helpers.each(this.data.datasets, function(dataset) {
helpers.each(dataset.data, function(value, index) {
if (value === null) return;
if (helpers.isDatasetVisible(dataset)) {
helpers.each(dataset.data, function(rawValue, index) {
var value = this.getRightValue(rawValue);
if (isNaN(value)) {
return;
}
if (this.min === null) {
this.min = value;
} else if (value < this.min) {
this.min = value;
}
if (this.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);
if (this.max === null) {
this.max = value;
} else if (value > this.max) {
this.max = value;
}
}, this);
}
}, this);
if (this.min === this.max) {
@@ -201,9 +206,7 @@
for (i = 0; i < this.getValueCount(); i++) {
// 5px to space the text slightly out - similar to what we do in the draw function.
pointPosition = this.getPointPosition(i, largestPossibleRadius);
textWidth = this.ctx.measureText(helpers.template(this.options.ticks.template, {
value: this.data.labels[i]
})).width + 5;
textWidth = this.ctx.measureText(this.options.ticks.callback(this.data.labels[i])).width + 5;
if (i === 0 || i === this.getValueCount() / 2) {
// If we're at index zero, or exactly the middle, we're at exactly the top/bottom
// of the radar chart, so text will be aligned centrally, so we'll half it and compare
@@ -277,8 +280,8 @@
getPointPosition: function(index, distanceFromCenter) {
var thisAngle = this.getIndexAngle(index);
return {
x: (Math.cos(thisAngle) * distanceFromCenter) + this.xCenter,
y: (Math.sin(thisAngle) * distanceFromCenter) + this.yCenter
x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + this.xCenter,
y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + this.yCenter
};
},
getPointPositionForValue: function(index, value) {
+80 -20
Ver Arquivo
@@ -74,23 +74,73 @@
};
var TimeScale = Chart.Scale.extend({
getLabelMoment: function(datasetIndex, index) {
return this.labelMoments[datasetIndex][index];
},
buildLabelMoments: function() {
// Only parse these once. If the dataset does not have data as x,y pairs, we will use
// these
var scaleLabelMoments = [];
if (this.data.labels && this.data.labels.length > 0) {
helpers.each(this.data.labels, function(label, index) {
var labelMoment = this.parseTime(label);
if (this.options.time.round) {
labelMoment.startOf(this.options.time.round);
}
scaleLabelMoments.push(labelMoment);
}, this);
if (this.options.time.min) {
this.firstTick = this.parseTime(this.options.time.min);
} else {
this.firstTick = moment.min.call(this, scaleLabelMoments);
}
if (this.options.time.max) {
this.lastTick = this.parseTime(this.options.time.max);
} else {
this.lastTick = moment.max.call(this, scaleLabelMoments);
}
} else {
this.firstTick = null;
this.lastTick = null;
}
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
var momentsForDataset = [];
if (typeof dataset.data[0] === 'object') {
helpers.each(dataset.data, function(value, index) {
var labelMoment = this.parseTime(this.getRightValue(value));
if (this.options.time.round) {
labelMoment.startOf(this.options.time.round);
}
momentsForDataset.push(labelMoment);
// May have gone outside the scale ranges, make sure we keep the first and last ticks updated
this.firstTick = this.firstTick !== null ? moment.min(this.firstTick, labelMoment) : labelMoment;
this.lastTick = this.lastTick !== null ? moment.max(this.lastTick, labelMoment) : labelMoment;
}, this);
} else {
// We have no labels. Use the ones from the scale
momentsForDataset = scaleLabelMoments;
}
this.labelMoments.push(momentsForDataset);
}, this);
// We will modify these, so clone for later
this.firstTick = this.firstTick.clone();
this.lastTick = this.lastTick.clone();
},
buildTicks: function(index) {
this.ticks = [];
this.labelMoments = [];
// Parse each label into a moment
this.data.labels.forEach(function(label, index) {
var labelMoment = this.parseTime(label);
if (this.options.time.round) {
labelMoment.startOf(this.options.time.round);
}
this.labelMoments.push(labelMoment);
}, this);
// Find the first and last moments, and range
this.firstTick = moment.min.call(this, this.labelMoments).clone();
this.lastTick = moment.max.call(this, this.labelMoments).clone();
this.buildLabelMoments();
// Set unit override if applicable
if (this.options.time.unit) {
@@ -124,11 +174,11 @@
this.lastTick.endOf(this.tickUnit);
this.smallestLabelSeparation = this.width;
var i = 0;
for (i = 1; i < this.labelMoments.length; i++) {
this.smallestLabelSeparation = Math.min(this.smallestLabelSeparation, this.labelMoments[i].diff(this.labelMoments[i - 1], this.tickUnit, true));
}
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
for (var i = 1; i < this.labelMoments[datasetIndex].length; i++) {
this.smallestLabelSeparation = Math.min(this.smallestLabelSeparation, this.labelMoments[datasetIndex][i].diff(this.labelMoments[datasetIndex][i - 1], this.tickUnit, true));
}
}, this);
// Tick displayFormat override
if (this.options.time.displayFormat) {
@@ -136,10 +186,20 @@
}
// For every unit in between the first and last moment, create a moment and add it to the ticks tick
for (i = 0; i <= this.tickRange; ++i) {
for (var i = 0; i <= this.tickRange; ++i) {
this.ticks.push(this.firstTick.clone().add(i, this.tickUnit));
}
},
// Get tooltip label
getLabelForIndex: function(index, datasetIndex) {
var label = this.data.labels && index < this.data.labels.length ? this.data.labels[index] : '';
if (typeof this.data.datasets[datasetIndex].data[0] === 'object') {
label = this.getRightValue(this.data.datasets[datasetIndex].data[index]);
}
return label;
},
convertTicksToLabels: function() {
this.ticks = this.ticks.map(function(tick, index, ticks) {
var formattedTick = tick.format(this.options.time.displayFormat ? this.options.time.displayFormat : time.unit[this.tickUnit].display);
@@ -152,8 +212,8 @@
}, this);
},
getPixelForValue: function(value, index, datasetIndex, includeOffset) {
var offset = this.labelMoments[index].diff(this.firstTick, this.tickUnit, true);
var labelMoment = this.getLabelMoment(datasetIndex, index);
var offset = labelMoment.diff(this.firstTick, this.tickUnit, true);
var decimal = offset / this.tickRange;
+38 -5
Ver Arquivo
@@ -78,6 +78,39 @@ describe('Bar controller tests', function() {
expect(controller.getBarCount()).toBe(2);
});
it('should correctly get the bar index accounting for hidden datasets', function() {
var chart = {
data: {
datasets: [{
}, {
hidden: true
}, {
type: 'line'
}, {
}]
},
config: {
type: 'bar'
},
options: {
scales: {
xAxes: [{
id: 'firstXScaleID'
}],
yAxes: [{
id: 'firstYScaleID'
}]
}
}
};
var controller = new Chart.controllers.bar(chart, 1);
expect(controller.getBarIndex(0)).toBe(0);
expect(controller.getBarIndex(3)).toBe(1);
});
it('Should create rectangle elements for each data item during initialization', function() {
var chart = {
data: {
@@ -229,13 +262,13 @@ describe('Bar controller tests', function() {
expect(bar1._xScale).toBe(chart.scales.firstXScaleID);
expect(bar1._yScale).toBe(chart.scales.firstYScaleID);
expect(bar1._model).toEqual({
x: 106.80000000000003,
x: 103.60000000000001,
y: 194,
label: 'label1',
datasetLabel: 'dataset2',
base: 194,
width: 12.240000000000002,
width: 13.680000000000001,
backgroundColor: 'rgb(255, 0, 0)',
borderColor: 'rgb(0, 0, 255)',
borderWidth: 2,
@@ -246,13 +279,13 @@ describe('Bar controller tests', function() {
expect(bar2._xScale).toBe(chart.scales.firstXScaleID);
expect(bar2._yScale).toBe(chart.scales.firstYScaleID);
expect(bar2._model).toEqual({
x: 140.8,
y: -15,
x: 141.6,
y: 6,
label: 'label2',
datasetLabel: 'dataset2',
base: 194,
width: 12.240000000000002,
width: 13.680000000000001,
backgroundColor: 'rgb(255, 0, 0)',
borderColor: 'rgb(0, 0, 255)',
borderWidth: 2,
+21 -19
Ver Arquivo
@@ -68,6 +68,8 @@ describe('Doughnut controller tests', function() {
},
data: {
datasets: [{
hidden: true
}, {
data: [10, 15, 0, 4]
}, {
data: [1]
@@ -94,10 +96,10 @@ describe('Doughnut controller tests', function() {
}
};
var controller = new Chart.controllers.doughnut(chart, 0);
var controller = new Chart.controllers.doughnut(chart, 1);
controller.reset(); // reset first
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
expect(chart.data.datasets[1].metaData[0]._model).toEqual({
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
@@ -106,7 +108,7 @@ describe('Doughnut controller tests', function() {
innerRadius: 36.75,
});
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
expect(chart.data.datasets[1].metaData[1]._model).toEqual({
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
@@ -115,7 +117,7 @@ describe('Doughnut controller tests', function() {
innerRadius: 36.75,
});
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
expect(chart.data.datasets[1].metaData[2]._model).toEqual({
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
@@ -124,7 +126,7 @@ describe('Doughnut controller tests', function() {
innerRadius: 36.75,
});
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
expect(chart.data.datasets[1].metaData[3]._model).toEqual({
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
@@ -135,7 +137,7 @@ describe('Doughnut controller tests', function() {
controller.update();
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
expect(chart.data.datasets[1].metaData[0]._model).toEqual({
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
@@ -152,7 +154,7 @@ describe('Doughnut controller tests', function() {
label: 'label0',
});
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
expect(chart.data.datasets[1].metaData[1]._model).toEqual({
x: 50,
y: 100,
startAngle: 0.5958182130626666,
@@ -169,7 +171,7 @@ describe('Doughnut controller tests', function() {
label: 'label1'
});
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
expect(chart.data.datasets[1].metaData[2]._model).toEqual({
x: 50,
y: 100,
startAngle: 3.8457400228490113,
@@ -186,7 +188,7 @@ describe('Doughnut controller tests', function() {
label: 'label2'
});
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
expect(chart.data.datasets[1].metaData[3]._model).toEqual({
x: 50,
y: 100,
startAngle: 3.8457400228490113,
@@ -204,24 +206,24 @@ describe('Doughnut controller tests', function() {
});
// Change the amount of data and ensure that arcs are updated accordingly
chart.data.datasets[0].data = [1, 2]; // remove 2 elements from dataset 0
chart.data.datasets[1].data = [1, 2]; // remove 2 elements from dataset 0
controller.buildOrUpdateElements();
controller.update();
expect(chart.data.datasets[0].metaData.length).toBe(2);
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[1].metaData.length).toBe(2);
expect(chart.data.datasets[1].metaData[0] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[1].metaData[1] instanceof Chart.elements.Arc).toBe(true);
// Add data
chart.data.datasets[0].data = [1, 2, 3, 4];
chart.data.datasets[1].data = [1, 2, 3, 4];
controller.buildOrUpdateElements();
controller.update();
expect(chart.data.datasets[0].metaData.length).toBe(4);
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[1].metaData.length).toBe(4);
expect(chart.data.datasets[1].metaData[0] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[1].metaData[1] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[1].metaData[2] instanceof Chart.elements.Arc).toBe(true);
expect(chart.data.datasets[1].metaData[3] instanceof Chart.elements.Arc).toBe(true);
});
it ('should draw all arcs', function() {
+50 -63
Ver Arquivo
@@ -103,7 +103,7 @@ describe('Line controller tests', function() {
expect(chart.data.datasets[0].metaData.length).toBe(3);
});
it ('should draw all elements', function() {
it('should draw all elements', function() {
var chart = {
data: {
datasets: [{
@@ -141,7 +141,7 @@ describe('Line controller tests', function() {
expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
});
it ('should update elements', function() {
it('should update elements', function() {
var data = {
datasets: [{
data: [10, 15, 0, -4],
@@ -210,7 +210,6 @@ describe('Line controller tests', function() {
borderJoinStyle: 'bevel',
borderWidth: 1.2,
fill: true,
skipNull: true,
tension: 0.1,
},
point: {
@@ -251,8 +250,6 @@ describe('Line controller tests', function() {
borderJoinStyle: 'bevel',
borderWidth: 1.2,
fill: true,
drawNull: undefined,
skipNull: true,
tension: 0.1,
scaleTop: 0,
@@ -268,15 +265,15 @@ describe('Line controller tests', function() {
radius: 3,
skip: false,
tension: 0.1,
// Point
x: 63,
x: 71,
y: 62,
// Control points
controlPointPreviousX: 63,
controlPointPreviousX: 71,
controlPointPreviousY: 62,
controlPointNextX: 67.5,
controlPointNextX: 76,
controlPointNextY: 57.3,
});
@@ -288,16 +285,16 @@ describe('Line controller tests', function() {
radius: 3,
skip: false,
tension: 0.1,
// Point
x: 108,
x: 121,
y: 15,
// Control points
controlPointPreviousX: 105.27827106822767,
controlPointPreviousY: 12.125364948465183,
controlPointNextX: 114.17827106822767,
controlPointNextY: 21.52536494846518,
controlPointPreviousX: 117.82889384189087,
controlPointPreviousY: 12.04867347661131,
controlPointNextX: 127.92889384189088,
controlPointNextY: 21.44867347661131,
});
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
@@ -308,16 +305,16 @@ describe('Line controller tests', function() {
radius: 3,
skip: false,
tension: 0.1,
// Point
x: 152,
x: 172,
y: 156,
// Control points
controlPointPreviousX: 145.63719249781943,
controlPointPreviousY: 143.20289277651324,
controlPointNextX: 154.53719249781943,
controlPointNextY: 161.10289277651324,
controlPointPreviousX: 164.8815225337256,
controlPointPreviousY: 143.38408449046415,
controlPointNextX: 174.98152253372558,
controlPointNextY: 161.28408449046415,
});
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
@@ -328,15 +325,15 @@ describe('Line controller tests', function() {
radius: 3,
skip: false,
tension: 0.1,
// Point
x: 197,
x: 222,
y: 194,
// Control points
controlPointPreviousX: 192.5,
controlPointPreviousX: 217,
controlPointPreviousY: 190.2,
controlPointNextX: 197,
controlPointNextX: 222,
controlPointNextY: 194,
});
@@ -350,8 +347,6 @@ describe('Line controller tests', function() {
chart.data.datasets[0].borderDashOffset = 7;
chart.data.datasets[0].borderJoinStyle = 'miter';
chart.data.datasets[0].fill = false;
chart.data.datasets[0].skipNull = false;
chart.data.datasets[0].drawNull = true;
// point styles
chart.data.datasets[0].radius = 22;
@@ -371,8 +366,6 @@ describe('Line controller tests', function() {
borderJoinStyle: 'miter',
borderWidth: 0.55,
fill: false,
drawNull: true,
skipNull: false,
tension: 0.2,
scaleTop: 0,
@@ -388,15 +381,15 @@ describe('Line controller tests', function() {
radius: 22,
skip: false,
tension: 0.2,
// Point
x: 63,
x: 71,
y: 62,
// Control points
controlPointPreviousX: 63,
controlPointPreviousX: 71,
controlPointPreviousY: 62,
controlPointNextX: 72,
controlPointNextX: 81,
controlPointNextY: 52.6,
});
@@ -408,16 +401,16 @@ describe('Line controller tests', function() {
radius: 22,
skip: false,
tension: 0.2,
// Point
x: 108,
x: 121,
y: 15,
// Control points
controlPointPreviousX: 102.55654213645535,
controlPointPreviousY: 9.250729896930364,
controlPointNextX: 120.35654213645535,
controlPointNextY: 28.050729896930367,
controlPointPreviousX: 114.65778768378175,
controlPointPreviousY: 9.097346953222619,
controlPointNextX: 134.85778768378177,
controlPointNextY: 27.897346953222623,
});
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
@@ -428,16 +421,16 @@ describe('Line controller tests', function() {
radius: 22,
skip: false,
tension: 0.2,
// Point
x: 152,
x: 172,
y: 156,
// Control points
controlPointPreviousX: 139.27438499563885,
controlPointPreviousY: 130.40578555302648,
controlPointNextX: 157.07438499563887,
controlPointNextY: 166.20578555302646,
controlPointPreviousX: 157.76304506745115,
controlPointPreviousY: 130.76816898092827,
controlPointNextX: 177.96304506745116,
controlPointNextY: 166.56816898092828,
});
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
@@ -448,15 +441,15 @@ describe('Line controller tests', function() {
radius: 22,
skip: false,
tension: 0.2,
// Point
x: 197,
x: 222,
y: 194,
// Control points
controlPointPreviousX: 188,
controlPointPreviousX: 212,
controlPointPreviousY: 186.4,
controlPointNextX: 197,
controlPointNextX: 222,
controlPointNextY: 194,
});
@@ -471,8 +464,6 @@ describe('Line controller tests', function() {
borderDashOffset: 4.4,
borderJoinStyle: 'round',
fill: true,
skipNull: true,
drawNull: false,
};
// point styles
@@ -497,8 +488,6 @@ describe('Line controller tests', function() {
borderJoinStyle: 'round',
borderWidth: 0.3,
fill: true,
drawNull: true,
skipNull: false,
tension: 0.25,
scaleTop: 0,
@@ -514,20 +503,20 @@ describe('Line controller tests', function() {
radius: 2.2,
skip: true,
tension: 0.15,
// Point
x: 63,
x: 71,
y: 62,
// Control points
controlPointPreviousX: 63,
controlPointPreviousX: 71,
controlPointPreviousY: 62,
controlPointNextX: 69.75,
controlPointNextX: 78.5,
controlPointNextY: 54.95,
});
});
it ('should handle number of data point changes in update', function() {
it('should handle number of data point changes in update', function() {
var data = {
datasets: [{
data: [10, 15, 0, -4],
@@ -596,7 +585,6 @@ describe('Line controller tests', function() {
borderJoinStyle: 'bevel',
borderWidth: 1.2,
fill: true,
skipNull: true,
tension: 0.1,
},
point: {
@@ -643,7 +631,7 @@ describe('Line controller tests', function() {
expect(chart.data.datasets[0].metaData[4] instanceof Chart.elements.Point).toBe(true);
});
it ('should set point hover styles', function() {
it('should set point hover styles', function() {
var data = {
datasets: [{
data: [10, 15, 0, -4],
@@ -777,7 +765,7 @@ describe('Line controller tests', function() {
expect(point._model.radius).toBe(4.4);
});
it ('should remove hover styles', function() {
it('should remove hover styles', function() {
var data = {
datasets: [{
data: [10, 15, 0, -4],
@@ -846,7 +834,6 @@ describe('Line controller tests', function() {
borderJoinStyle: 'bevel',
borderWidth: 1.2,
fill: true,
skipNull: true,
tension: 0.1,
},
point: {
@@ -915,4 +902,4 @@ describe('Line controller tests', function() {
expect(point._model.borderWidth).toBe(5.5);
expect(point._model.radius).toBe(4.4);
});
});
});
+65 -31
Ver Arquivo
@@ -150,17 +150,18 @@ describe('Core helper tests', function() {
var merged = helpers.configMerge(baseConfig, toMerge);
expect(merged).toEqual({
arrayProp: [{
prop1: 'myProp1',
prop2: 56,
prop3: 'prop3'
},
2, {
prop1: 'myProp1'
}],
prop1: 'myProp1',
prop2: 56,
prop3: 'prop3'
},
2, {
prop1: 'myProp1'
}
],
});
});
it ('Should merge scale configs', function() {
it('Should merge scale configs', function() {
var baseConfig = {
scales: {
prop1: {
@@ -243,7 +244,7 @@ describe('Core helper tests', function() {
padding: 10,
reverse: false,
show: true,
template: "<%=value%>"
callback: merged.scales.yAxes[1].ticks.callback, // make it nicer, then check explicitly below
},
type: 'linear'
}, {
@@ -280,25 +281,31 @@ describe('Core helper tests', function() {
padding: 10,
reverse: false,
show: true,
template: "<%=value%>"
callback: merged.scales.yAxes[2].ticks.callback, // make it nicer, then check explicitly below
},
type: 'linear'
}]
}
});
// Are these actually functions
expect(merged.scales.yAxes[1].ticks.callback).toEqual(jasmine.any(Function));
expect(merged.scales.yAxes[2].ticks.callback).toEqual(jasmine.any(Function));
});
it ('should get value or default', function() {
it('should get value or default', function() {
expect(helpers.getValueAtIndexOrDefault(98, 0, 56)).toBe(98);
expect(helpers.getValueAtIndexOrDefault(0, 0, 56)).toBe(0);
expect(helpers.getValueAtIndexOrDefault(0, 0, 56)).toBe(0);
expect(helpers.getValueAtIndexOrDefault(undefined, undefined, 56)).toBe(56);
expect(helpers.getValueAtIndexOrDefault([1, 2, 3], 1, 100)).toBe(2);
expect(helpers.getValueAtIndexOrDefault([1, 2, 3], 3, 100)).toBe(100);
});
it ('should filter an array', function() {
it('should filter an array', function() {
var data = [-10, 0, 6, 0, 7];
var callback = function(item) { return item > 2};
var callback = function(item) {
return item > 2
};
expect(helpers.where(data, callback)).toEqual([6, 7]);
expect(helpers.findNextWhere(data, callback)).toEqual(6);
expect(helpers.findNextWhere(data, callback, 2)).toBe(7);
@@ -308,26 +315,26 @@ describe('Core helper tests', function() {
expect(helpers.findPreviousWhere(data, callback, 0)).toBe(undefined);
});
it ('Should get the correct sign', function() {
it('Should get the correct sign', function() {
expect(helpers.sign(0)).toBe(0);
expect(helpers.sign(10)).toBe(1);
expect(helpers.sign(-5)).toBe(-1);
});
it ('should do a log10 operation', function() {
it('should do a log10 operation', function() {
expect(helpers.log10(0)).toBe(-Infinity);
expect(helpers.log10(1)).toBe(0);
expect(helpers.log10(1000)).toBe(3);
});
it ('Should generate ids', function() {
it('Should generate ids', function() {
expect(helpers.uid()).toBe('chart-0');
expect(helpers.uid()).toBe('chart-1');
expect(helpers.uid()).toBe('chart-2');
expect(helpers.uid()).toBe('chart-3');
});
it ('should detect a number', function() {
it('should detect a number', function() {
expect(helpers.isNumber(123)).toBe(true);
expect(helpers.isNumber('123')).toBe(true);
expect(helpers.isNumber(null)).toBe(false);
@@ -336,37 +343,55 @@ describe('Core helper tests', function() {
expect(helpers.isNumber('cbc')).toBe(false);
});
it ('should convert between radians and degrees', function() {
it('should convert between radians and degrees', function() {
expect(helpers.toRadians(180)).toBe(Math.PI);
expect(helpers.toRadians(90)).toBe(0.5 * Math.PI);
expect(helpers.toDegrees(Math.PI)).toBe(180);
expect(helpers.toDegrees(Math.PI * 3 /2)).toBe(270);
expect(helpers.toDegrees(Math.PI * 3 / 2)).toBe(270);
});
it ('should get an angle from a point', function() {
it('should get an angle from a point', function() {
var center = {
x: 0,
y: 0
};
expect(helpers.getAngleFromPoint(center, {x: 0, y: 10})).toEqual({
expect(helpers.getAngleFromPoint(center, {
x: 0,
y: 10
})).toEqual({
angle: Math.PI / 2,
distance: 10,
});
expect(helpers.getAngleFromPoint(center, {x: Math.sqrt(2), y: Math.sqrt(2)})).toEqual({
expect(helpers.getAngleFromPoint(center, {
x: Math.sqrt(2),
y: Math.sqrt(2)
})).toEqual({
angle: Math.PI / 4,
distance: 2
});
expect(helpers.getAngleFromPoint(center, {x: -1.0 * Math.sqrt(2), y: -1.0 * Math.sqrt(2)})).toEqual({
expect(helpers.getAngleFromPoint(center, {
x: -1.0 * Math.sqrt(2),
y: -1.0 * Math.sqrt(2)
})).toEqual({
angle: Math.PI * 1.25,
distance: 2
});
});
it ('should spline curves', function() {
expect(helpers.splineCurve({x: 0, y: 0}, {x: 1, y: 1}, { x: 2, y: 0}, 0)).toEqual({
it('should spline curves', function() {
expect(helpers.splineCurve({
x: 0,
y: 0
}, {
x: 1,
y: 1
}, {
x: 2,
y: 0
}, 0)).toEqual({
previous: {
x: 1,
y: 1,
@@ -377,7 +402,16 @@ describe('Core helper tests', function() {
}
});
expect(helpers.splineCurve({x: 0, y: 0}, {x: 1, y: 1}, { x: 2, y: 0}, 1)).toEqual({
expect(helpers.splineCurve({
x: 0,
y: 0
}, {
x: 1,
y: 1
}, {
x: 2,
y: 0
}, 1)).toEqual({
previous: {
x: 0,
y: 1,
@@ -389,7 +423,7 @@ describe('Core helper tests', function() {
});
});
it ('should get the next or previous item in an array', function() {
it('should get the next or previous item in an array', function() {
var testData = [0, 1, 2];
expect(helpers.nextItem(testData, 0, false)).toEqual(1);
@@ -404,7 +438,7 @@ describe('Core helper tests', function() {
expect(helpers.previousItem(testData, 1, true)).toEqual(0);
});
it ('should clear a canvas', function() {
it('should clear a canvas', function() {
var context = window.createMockContext();
helpers.clear({
width: 100,
@@ -418,7 +452,7 @@ describe('Core helper tests', function() {
}]);
});
it ('should draw a rounded rectangle', function() {
it('should draw a rounded rectangle', function() {
var context = window.createMockContext();
helpers.drawRoundedRectangle(context, 10, 20, 30, 40, 5);
@@ -457,4 +491,4 @@ describe('Core helper tests', function() {
args: []
}])
});
});
});
+257
Ver Arquivo
@@ -0,0 +1,257 @@
// Tests of the scale service
describe('Test the scale service', function() {
it('should fit a simple chart with 2 scales', function() {
var chartInstance = {
scales: [],
};
var xScaleID = 'xScale';
var yScaleID = 'yScale';
var mockData = {
datasets: [{
yAxisID: yScaleID,
data: [10, 5, 0, 25, 78, -10]
}],
labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
};
var mockContext = window.createMockContext();
var xScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
var XConstructor = Chart.scaleService.getScaleConstructor('category');
var xScale = new XConstructor({
ctx: mockContext,
options: xScaleConfig,
data: mockData,
id: xScaleID
});
var yScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
var YConstructor = Chart.scaleService.getScaleConstructor('linear');
var yScale = new YConstructor({
ctx: mockContext,
options: yScaleConfig,
data: mockData,
id: yScaleID
});
chartInstance.scales.push(xScale);
chartInstance.scales.push(yScale);
var canvasWidth = 250;
var canvasHeight = 150;
Chart.scaleService.update(chartInstance, canvasWidth, canvasHeight);
expect(chartInstance.chartArea).toEqual({
left: 45,
right: 245,
top: 5,
bottom: 76.0423977855504,
});
// Is xScale at the right spot
expect(xScale.left).toBe(45);
expect(xScale.right).toBe(245);
expect(xScale.top).toBe(76.0423977855504);
expect(xScale.bottom).toBe(145);
expect(xScale.labelRotation).toBe(55);
// Is yScale at the right spot
expect(yScale.left).toBe(5);
expect(yScale.right).toBe(45);
expect(yScale.top).toBe(5);
expect(yScale.bottom).toBe(76.0423977855504);
});
it('should fit scales that are in the top and right positions', function() {
var chartInstance = {
scales: [],
};
var xScaleID = 'xScale';
var yScaleID = 'yScale';
var mockData = {
datasets: [{
yAxisID: yScaleID,
data: [10, 5, 0, 25, 78, -10]
}],
labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
};
var mockContext = window.createMockContext();
var xScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
xScaleConfig.position = 'top';
var XConstructor = Chart.scaleService.getScaleConstructor('category');
var xScale = new XConstructor({
ctx: mockContext,
options: xScaleConfig,
data: mockData,
id: xScaleID
});
var yScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
yScaleConfig.position = 'right';
var YConstructor = Chart.scaleService.getScaleConstructor('linear');
var yScale = new YConstructor({
ctx: mockContext,
options: yScaleConfig,
data: mockData,
id: yScaleID
});
chartInstance.scales.push(xScale);
chartInstance.scales.push(yScale);
var canvasWidth = 250;
var canvasHeight = 150;
Chart.scaleService.update(chartInstance, canvasWidth, canvasHeight);
expect(chartInstance.chartArea).toEqual({
left: 5,
right: 205,
top: 73.9576022144496,
bottom: 145,
});
// Is xScale at the right spot
expect(xScale.left).toBe(5);
expect(xScale.right).toBe(205);
expect(xScale.top).toBe(5);
expect(xScale.bottom).toBe(73.9576022144496);
expect(xScale.labelRotation).toBe(55);
// Is yScale at the right spot
expect(yScale.left).toBe(205);
expect(yScale.right).toBe(245);
expect(yScale.top).toBe(73.9576022144496);
expect(yScale.bottom).toBe(145);
});
it('should fit multiple axes in the same position', function() {
var chartInstance = {
scales: [],
};
var xScaleID = 'xScale';
var yScaleID1 = 'yScale1';
var yScaleID2 = 'yScale2';
var mockData = {
datasets: [{
yAxisID: yScaleID1,
data: [10, 5, 0, 25, 78, -10]
}, {
yAxisID: yScaleID2,
data: [-19, -20, 0, -99, -50, 0]
}],
labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
};
var mockContext = window.createMockContext();
var xScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
var XConstructor = Chart.scaleService.getScaleConstructor('category');
var xScale = new XConstructor({
ctx: mockContext,
options: xScaleConfig,
data: mockData,
id: xScaleID
});
var yScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
var YConstructor = Chart.scaleService.getScaleConstructor('linear');
var yScale1 = new YConstructor({
ctx: mockContext,
options: yScaleConfig,
data: mockData,
id: yScaleID1
});
var yScale2 = new YConstructor({
ctx: mockContext,
options: yScaleConfig,
data: mockData,
id: yScaleID2
});
chartInstance.scales.push(xScale);
chartInstance.scales.push(yScale1);
chartInstance.scales.push(yScale2);
var canvasWidth = 250;
var canvasHeight = 150;
Chart.scaleService.update(chartInstance, canvasWidth, canvasHeight);
expect(chartInstance.chartArea).toEqual({
left: 95,
right: 245,
top: 5,
bottom: 70.01536896070459,
});
// Is xScale at the right spot
expect(xScale.left).toBe(95);
expect(xScale.right).toBe(245);
expect(xScale.top).toBe(70.01536896070459);
expect(xScale.bottom).toBe(145);
// Are yScales at the right spot
expect(yScale1.left).toBe(5);
expect(yScale1.right).toBe(45);
expect(yScale1.top).toBe(5);
expect(yScale1.bottom).toBe(70.01536896070459);
expect(yScale2.left).toBe(45);
expect(yScale2.right).toBe(95);
expect(yScale2.top).toBe(5);
expect(yScale2.bottom).toBe(70.01536896070459);
});
// This is an oddball case. What happens is, when the scales are fit the first time they must fit within the assigned size. In this case,
// the labels on the xScale need to rotate to fit. However, when the scales are fit again after the width of the left axis is determined,
// the labels do not need to rotate. Previously, the chart was too small because the chartArea did not expand to take up the space freed up
// due to the lack of label rotation
it('should fit scales that overlap the chart area', function() {
var chartInstance = {
scales: [],
};
var scaleID = 'scaleID';
var mockData = {
datasets: [{
yAxisID: scaleID,
data: [10, 5, 0, 25, 78, -10]
}, {
yAxisID: scaleID,
data: [-19, -20, 0, -99, -50, 0]
}],
labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
};
var mockContext = window.createMockContext();
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
var scale = new ScaleConstructor({
ctx: mockContext,
options: scaleConfig,
data: mockData,
id: scaleID
});
chartInstance.scales.push(scale);
var canvasWidth = 300;
var canvasHeight = 350;
Chart.scaleService.update(chartInstance, canvasWidth, canvasHeight);
expect(chartInstance.chartArea).toEqual({
left: 5,
right: 295,
top: 5,
bottom: 345,
});
expect(scale.left).toBe(5);
expect(scale.right).toBe(295);
expect(scale.top).toBe(5);
expect(scale.bottom).toBe(345);
expect(scale.width).toBe(290);
expect(scale.height).toBe(340)
});
});
+58 -24
Ver Arquivo
@@ -1,6 +1,6 @@
// Tests for the line element
describe('Line element tests', function() {
it ('should be constructed', function() {
it('should be constructed', function() {
var line = new Chart.elements.Line({
_datasetindex: 2,
_points: [1, 2, 3, 4]
@@ -11,7 +11,7 @@ describe('Line element tests', function() {
expect(line._points).toEqual([1, 2, 3, 4]);
});
it ('should draw with default settings', function() {
it('should draw with default settings', function() {
var mockContext = window.createMockContext();
// Create our points
@@ -21,7 +21,7 @@ describe('Line element tests', function() {
_index: 0,
_view: {
x: 0,
y: 10
y: 10,
}
}));
points.push(new Chart.elements.Point({
@@ -29,7 +29,7 @@ describe('Line element tests', function() {
_index: 1,
_view: {
x: 5,
y: 0
y: 0,
}
}));
points.push(new Chart.elements.Point({
@@ -37,7 +37,7 @@ describe('Line element tests', function() {
_index: 2,
_view: {
x: 15,
y: -10
y: -10,
}
}));
points.push(new Chart.elements.Point({
@@ -45,7 +45,7 @@ describe('Line element tests', function() {
_index: 3,
_view: {
x: 19,
y: -5
y: -5,
}
}));
@@ -59,8 +59,9 @@ describe('Line element tests', function() {
_view: {
fill: false, // don't want to fill
tension: 0.0, // no bezier curve for now
scaleZero: 0
}
})
});
line.draw();
@@ -69,6 +70,9 @@ describe('Line element tests', function() {
args: [],
}, {
name: 'moveTo',
args: [0, 0]
}, {
name: 'lineTo',
args: [0, 10]
}, {
name: 'lineTo',
@@ -84,7 +88,9 @@ describe('Line element tests', function() {
args: ['butt']
}, {
name: 'setLineDash',
args: [[]]
args: [
[]
]
}, {
name: 'setLineDashOffset',
args: [0.0]
@@ -102,6 +108,9 @@ describe('Line element tests', function() {
args: []
}, {
name: 'moveTo',
args: [0, 0]
}, {
name: 'lineTo',
args: [0, 10]
}, {
name: 'lineTo',
@@ -118,10 +127,10 @@ describe('Line element tests', function() {
}, {
name: 'restore',
args: []
}])
}]);
});
it ('should draw with custom settings', function() {
it('should draw with custom settings', function() {
var mockContext = window.createMockContext();
// Create our points
@@ -167,7 +176,7 @@ describe('Line element tests', function() {
_children: points,
// Need to provide some settings
_view: {
fill: true,
fill: true,
scaleZero: 2, // for filling lines
tension: 0.0, // no bezier curve for now
@@ -179,7 +188,7 @@ describe('Line element tests', function() {
borderWidth: 4,
backgroundColor: 'rgb(0, 0, 0)'
}
})
});
line.draw();
@@ -188,6 +197,9 @@ describe('Line element tests', function() {
args: [],
}, {
name: 'moveTo',
args: [0, 2]
}, {
name: 'lineTo',
args: [0, 10]
}, {
name: 'lineTo',
@@ -218,7 +230,9 @@ describe('Line element tests', function() {
args: ['round']
}, {
name: 'setLineDash',
args: [[2, 2]]
args: [
[2, 2]
]
}, {
name: 'setLineDashOffset',
args: [1.5]
@@ -236,6 +250,9 @@ describe('Line element tests', function() {
args: []
}, {
name: 'moveTo',
args: [0, 2]
}, {
name: 'lineTo',
args: [0, 10]
}, {
name: 'lineTo',
@@ -253,10 +270,10 @@ describe('Line element tests', function() {
name: 'restore',
args: []
}];
expect(mockContext.getCalls()).toEqual(expected)
expect(mockContext.getCalls()).toEqual(expected);
});
it ('should be able to draw with a loop back to the beginning point', function() {
it('should be able to draw with a loop back to the beginning point', function() {
var mockContext = window.createMockContext();
// Create our points
@@ -305,8 +322,9 @@ describe('Line element tests', function() {
_view: {
fill: false, // don't want to fill
tension: 0.0, // no bezier curve for now
scaleZero: 0,
}
})
});
line.draw();
@@ -315,6 +333,9 @@ describe('Line element tests', function() {
args: [],
}, {
name: 'moveTo',
args: [0, 0]
}, {
name: 'lineTo',
args: [0, 10]
}, {
name: 'lineTo',
@@ -333,7 +354,9 @@ describe('Line element tests', function() {
args: ['butt']
}, {
name: 'setLineDash',
args: [[]]
args: [
[]
]
}, {
name: 'setLineDashOffset',
args: [0.0]
@@ -351,6 +374,9 @@ describe('Line element tests', function() {
args: []
}, {
name: 'moveTo',
args: [0, 0]
}, {
name: 'lineTo',
args: [0, 10]
}, {
name: 'lineTo',
@@ -370,10 +396,10 @@ describe('Line element tests', function() {
}, {
name: 'restore',
args: []
}])
}]);
});
it ('should draw with bezier curves if tension > 0', function() {
it('should draw with bezier curves if tension > 0', function() {
var mockContext = window.createMockContext();
// Create our points
@@ -435,7 +461,7 @@ describe('Line element tests', function() {
_children: points,
// Need to provide some settings
_view: {
fill: true,
fill: true,
scaleZero: 2, // for filling lines
tension: 0.5, // have bezier curves
@@ -447,7 +473,7 @@ describe('Line element tests', function() {
borderWidth: 4,
backgroundColor: 'rgb(0, 0, 0)'
}
})
});
line.draw();
@@ -456,6 +482,9 @@ describe('Line element tests', function() {
args: [],
}, {
name: 'moveTo',
args: [0, 2]
}, {
name: 'lineTo',
args: [0, 10]
}, {
name: 'bezierCurveTo',
@@ -486,7 +515,9 @@ describe('Line element tests', function() {
args: ['round']
}, {
name: 'setLineDash',
args: [[2, 2]]
args: [
[2, 2]
]
}, {
name: 'setLineDashOffset',
args: [1.5]
@@ -504,6 +535,9 @@ describe('Line element tests', function() {
args: []
}, {
name: 'moveTo',
args: [0, 2]
}, {
name: 'lineTo',
args: [0, 10]
}, {
name: 'bezierCurveTo',
@@ -521,6 +555,6 @@ describe('Line element tests', function() {
name: 'restore',
args: []
}];
expect(mockContext.getCalls()).toEqual(expected)
expect(mockContext.getCalls()).toEqual(expected);
});
});
});
+13 -10
Ver Arquivo
@@ -43,9 +43,12 @@ describe('Category scale tests', function() {
padding: 10,
reverse: false,
show: true,
template: "<%=value%>"
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
}
});
// Is this actually a function
expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
});
it('Should generate ticks from the data labales', function() {
@@ -94,9 +97,9 @@ describe('Category scale tests', function() {
id: scaleID
});
var minSize = scale.update(200, 100);
var minSize = scale.update(600, 100);
expect(scale.width).toBe(200);
expect(scale.width).toBe(600);
expect(scale.height).toBe(28);
expect(scale.paddingTop).toBe(0);
expect(scale.paddingBottom).toBe(0);
@@ -105,28 +108,28 @@ describe('Category scale tests', function() {
expect(scale.labelRotation).toBe(0);
expect(minSize).toEqual({
width: 200,
width: 600,
height: 28,
});
scale.left = 5;
scale.top = 5;
scale.right = 205;
scale.right = 605;
scale.bottom = 33;
expect(scale.getPixelForValue(0, 0, 0, false)).toBe(33);
expect(scale.getPixelForValue(0, 0, 0, true)).toBe(45);
expect(scale.getPixelForValue(0, 0, 0, true)).toBe(85);
expect(scale.getPixelForValue(0, 4, 0, false)).toBe(132);
expect(scale.getPixelForValue(0, 4, 0, true)).toBe(145);
expect(scale.getPixelForValue(0, 4, 0, false)).toBe(452);
expect(scale.getPixelForValue(0, 4, 0, true)).toBe(505);
config.gridLines.offsetGridLines = false;
expect(scale.getPixelForValue(0, 0, 0, false)).toBe(33);
expect(scale.getPixelForValue(0, 0, 0, true)).toBe(33);
expect(scale.getPixelForValue(0, 4, 0, false)).toBe(157);
expect(scale.getPixelForValue(0, 4, 0, true)).toBe(157);
expect(scale.getPixelForValue(0, 4, 0, false)).toBe(557);
expect(scale.getPixelForValue(0, 4, 0, true)).toBe(557);
});
it ('should get the correct pixel for a value when vertical', function() {
+159 -47
Ver Arquivo
@@ -42,9 +42,11 @@ describe('Linear Scale', function() {
padding: 10,
reverse: false,
show: true,
template: "<%=value%>"
callback: defaultConfig.ticks.callback, // make this work nicer, then check below
}
});
expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
});
it('Should correctly determine the max & min data values', function() {
@@ -84,6 +86,44 @@ describe('Linear Scale', function() {
expect(scale.max).toBe(150);
});
it('Should correctly determine the max & min data values ignoring hidden datasets', function() {
var scaleID = 'myScale';
var mockData = {
datasets: [{
yAxisID: scaleID,
data: [10, 5, 0, -5, 78, -100]
}, {
yAxisID: 'second scale',
data: [-1000, 1000],
}, {
yAxisID: scaleID,
data: [150],
hidden: true
}]
};
var Constructor = Chart.scaleService.getScaleConstructor('linear');
var scale = new Constructor({
ctx: {},
options: Chart.scaleService.getScaleDefaults('linear'), // use default config for scale
data: mockData,
id: scaleID
});
expect(scale).not.toEqual(undefined); // must construct
expect(scale.min).toBe(undefined); // not yet set
expect(scale.max).toBe(undefined);
// Set arbitrary width and height for now
scale.width = 50;
scale.height = 400;
scale.buildTicks();
expect(scale.min).toBe(-100);
expect(scale.max).toBe(80);
});
it('Should correctly determine the max & min for scatter data', function() {
var scaleID = 'myScale';
@@ -178,6 +218,46 @@ describe('Linear Scale', function() {
expect(scale.max).toBe(200);
});
it('Should correctly determine the min and max data values when stacked mode is turned on and there are hidden datasets', function() {
var scaleID = 'myScale';
var mockData = {
datasets: [{
yAxisID: scaleID,
data: [10, 5, 0, -5, 78, -100]
}, {
yAxisID: 'second scale',
data: [-1000, 1000],
}, {
yAxisID: scaleID,
data: [150, 0, 0, -100, -10, 9]
}, {
yAxisID: scaleID,
data: [10, 20, 30, 40, 50, 60],
hidden: true
}]
};
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
config.stacked = true; // enable scale stacked mode
var Constructor = Chart.scaleService.getScaleConstructor('linear');
var scale = new Constructor({
ctx: {},
options: config,
data: mockData,
id: scaleID
});
// Set arbitrary width and height for now
scale.width = 50;
scale.height = 400;
scale.buildTicks();
expect(scale.min).toBe(-150);
expect(scale.max).toBe(200);
});
it('Should ensure that the scale has a max and min that are not equal', function() {
var scaleID = 'myScale';
@@ -332,6 +412,31 @@ describe('Linear Scale', function() {
expect(scale.ticks).toEqual(['80', '70', '60', '50', '40', '30', '20', '10', '0']);
});
it('should use the correct number of decimal places in the default format function', function() {
var scaleID = 'myScale';
var mockData = {
datasets: [{
yAxisID: scaleID,
data: [0.06, 0.005, 0, 0.025, 0.0078]
}, ]
};
var mockContext = window.createMockContext();
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
var Constructor = Chart.scaleService.getScaleConstructor('linear');
var scale = new Constructor({
ctx: mockContext,
options: config,
data: mockData,
id: scaleID
});
// Set arbitrary width and height for now
scale.update(50, 400);
expect(scale.ticks).toEqual(['0.06', '0.05', '0.04', '0.03', '0.02', '0.01', '0']);
});
it('Should build labels using the user supplied callback', function() {
var scaleID = 'myScale';
@@ -343,7 +448,7 @@ describe('Linear Scale', function() {
};
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
config.ticks.userCallback = function(value, index) {
config.ticks.callback = function(value, index) {
return index.toString();
};
@@ -500,51 +605,52 @@ describe('Linear Scale', function() {
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
config.position = "bottom";
var Constructor = Chart.scaleService.getScaleConstructor('linear');
var verticalScale = new Constructor({
var horizontalScale = new Constructor({
ctx: mockContext,
options: config,
data: mockData,
id: scaleID
});
var minSize = verticalScale.update(100, 300);
var minSize = horizontalScale.update(200, 300);
expect(minSize).toEqual({
width: 100,
width: 200,
height: 28,
});
expect(verticalScale.width).toBe(100);
expect(verticalScale.height).toBe(28);
expect(verticalScale.paddingTop).toBe(0);
expect(verticalScale.paddingBottom).toBe(0);
expect(verticalScale.paddingLeft).toBe(18);
expect(verticalScale.paddingRight).toBe(13);
expect(horizontalScale.width).toBe(200);
expect(horizontalScale.height).toBe(28);
expect(horizontalScale.paddingTop).toBe(0);
expect(horizontalScale.paddingBottom).toBe(0);
expect(horizontalScale.paddingLeft).toBe(13);
expect(horizontalScale.paddingRight).toBe(8);
expect(horizontalScale.labelRotation).toBe(0);
// Refit with margins to see the padding go away
minSize = verticalScale.update(100, 28, {
minSize = horizontalScale.update(200, 28, {
left: 10,
right: 6,
top: 15,
bottom: 3
});
expect(minSize).toEqual({
width: 100,
width: 200,
height: 28,
});
expect(verticalScale.paddingTop).toBe(0);
expect(verticalScale.paddingBottom).toBe(0);
expect(verticalScale.paddingLeft).toBe(8);
expect(verticalScale.paddingRight).toBe(7);
expect(horizontalScale.paddingTop).toBe(0);
expect(horizontalScale.paddingBottom).toBe(0);
expect(horizontalScale.paddingLeft).toBe(3);
expect(horizontalScale.paddingRight).toBe(2);
// Extra size when scale label showing
config.scaleLabel.show = true;
minSize = verticalScale.update(100, 300);
minSize = horizontalScale.update(200, 300);
expect(minSize).toEqual({
width: 100,
width: 200,
height: 46,
});
});
it('should draw correctly horizontally', function() {
it('Should draw correctly horizontally', function() {
var scaleID = 'myScale';
var mockData = {
@@ -566,8 +672,8 @@ describe('Linear Scale', function() {
id: scaleID
});
var minSize = horizontalScale.update(100, 300);
minSize = horizontalScale.update(100, 28, {
var minSize = horizontalScale.update(200, 300);
minSize = horizontalScale.update(200, 28, {
left: 10,
right: 6,
top: 15,
@@ -576,12 +682,12 @@ describe('Linear Scale', function() {
horizontalScale.left = 0;
horizontalScale.right = minSize.width;
horizontalScale.top = 0;
horizontalScale.bottom = minSize.height;
horizontalScale.top = 100;
horizontalScale.bottom = 100 + minSize.height;
var chartArea = {
top: 100,
bottom: 0,
top: 0,
bottom: 100,
left: 0,
right: minSize.width
};
@@ -602,16 +708,16 @@ describe('Linear Scale', function() {
"args": []
}, {
"name": "moveTo",
"args": [8.5, 0]
"args": [3.5, 100]
}, {
"name": "lineTo",
"args": [8.5, 10]
"args": [3.5, 110]
}, {
"name": "moveTo",
"args": [8.5, 100]
"args": [3.5, 0]
}, {
"name": "lineTo",
"args": [8.5, 0]
"args": [3.5, 100]
}, {
"name": "stroke",
"args": []
@@ -620,13 +726,13 @@ describe('Linear Scale', function() {
"args": []
}, {
"name": "translate",
"args": [8, 10]
"args": [3, 110]
}, {
"name": "rotate",
"args": [-0]
}, {
"name": "fillText",
"args": ["-10", 0, 0]
"args": ["-5", 0, 0]
}, {
"name": "restore",
"args": []
@@ -641,16 +747,16 @@ describe('Linear Scale', function() {
"args": []
}, {
"name": "moveTo",
"args": [51.5, 0]
"args": [101.5, 100]
}, {
"name": "lineTo",
"args": [51.5, 10]
"args": [101.5, 110]
}, {
"name": "moveTo",
"args": [51.5, 100]
"args": [101.5, 0]
}, {
"name": "lineTo",
"args": [51.5, 0]
"args": [101.5, 100]
}, {
"name": "stroke",
"args": []
@@ -659,7 +765,7 @@ describe('Linear Scale', function() {
"args": []
}, {
"name": "translate",
"args": [51, 10]
"args": [101, 110]
}, {
"name": "rotate",
"args": [-0]
@@ -680,16 +786,16 @@ describe('Linear Scale', function() {
"args": []
}, {
"name": "moveTo",
"args": [93.5, 0]
"args": [198.5, 100]
}, {
"name": "lineTo",
"args": [93.5, 10]
"args": [198.5, 110]
}, {
"name": "moveTo",
"args": [93.5, 100]
"args": [198.5, 0]
}, {
"name": "lineTo",
"args": [93.5, 0]
"args": [198.5, 100]
}, {
"name": "stroke",
"args": []
@@ -698,13 +804,13 @@ describe('Linear Scale', function() {
"args": []
}, {
"name": "translate",
"args": [93, 10]
"args": [198, 110]
}, {
"name": "rotate",
"args": [-0]
}, {
"name": "fillText",
"args": ["10", 0, 0]
"args": ["5", 0, 0]
}, {
"name": "restore",
"args": []
@@ -716,7 +822,7 @@ describe('Linear Scale', function() {
config.gridLines.drawOnChartArea = false;
config.ticks.show = false;
config.scaleLabel.show = true;
config.scaleLabel.labelString = 'myLabel'
config.scaleLabel.labelString = 'myLabel';
mockContext.resetCalls();
@@ -760,9 +866,12 @@ describe('Linear Scale', function() {
}, {
"name": "stroke",
"args": []
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["myLabel", 50, 22]
"args": ["myLabel", 100, 122]
}]);
// Turn off display
@@ -773,7 +882,7 @@ describe('Linear Scale', function() {
expect(mockContext.getCalls()).toEqual([]);
});
it('should draw correctly vertically', function() {
it('Should draw correctly vertically', function() {
var scaleID = 'myScale';
var mockData = {
@@ -1312,6 +1421,9 @@ describe('Linear Scale', function() {
}, {
"name": "rotate",
"args": [-1.5707963267948966]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["", 0, 0]
@@ -1320,4 +1432,4 @@ describe('Linear Scale', function() {
"args": []
}]);
});
});
});
+76 -1
Ver Arquivo
@@ -41,9 +41,12 @@ describe('Logarithmic Scale tests', function() {
padding: 10,
reverse: false,
show: true,
template: "<%var remain = value / (Math.pow(10, Math.floor(Chart.helpers.log10(value))));if (remain === 1 || remain === 2 || remain === 5) {%><%=value.toExponential()%><%} else {%><%= null %><%}%>",
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
},
});
// Is this actually a function
expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
});
it('Should correctly determine the max & min data values', function() {
@@ -80,6 +83,41 @@ describe('Logarithmic Scale tests', function() {
expect(scale.max).toBe(10000);
});
it('Should correctly determine the max & min data values when there are hidden datasets', function() {
var scaleID = 'myScale';
var mockData = {
datasets: [{
yAxisID: scaleID,
data: [10, 5, 5000, 78, 450]
}, {
yAxisID: 'second scale',
data: [1, 1000, 10, 100],
}, {
yAxisID: scaleID,
data: [50000],
hidden: true
}]
};
var mockContext = window.createMockContext();
var Constructor = Chart.scaleService.getScaleConstructor('logarithmic');
var scale = new Constructor({
ctx: mockContext,
options: Chart.scaleService.getScaleDefaults('logarithmic'), // use default config for scale
data: mockData,
id: scaleID
});
expect(scale).not.toEqual(undefined); // must construct
expect(scale.min).toBe(undefined); // not yet set
expect(scale.max).toBe(undefined);
scale.update(400, 400);
expect(scale.min).toBe(1);
expect(scale.max).toBe(10000);
});
it('Should correctly determine the max & min for scatter data', function() {
var scaleID = 'myScale';
@@ -164,6 +202,43 @@ describe('Logarithmic Scale tests', function() {
expect(scale.max).toBe(1000);
});
it('Should correctly determine the min and max data values when stacked mode is turned on ignoring hidden datasets', function() {
var scaleID = 'myScale';
var mockData = {
datasets: [{
yAxisID: scaleID,
data: [10, 5, 1, 5, 78, 100]
}, {
yAxisID: 'second scale',
data: [-1000, 1000],
}, {
yAxisID: scaleID,
data: [150, 10, 10, 100, 10, 9]
}, {
yAxisID: scaleID,
data: [10000, 10000, 10000, 10000, 10000, 10000],
hidden: true
}]
};
var config = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('logarithmic'));
config.stacked = true; // enable scale stacked mode
var mockContext = window.createMockContext();
var Constructor = Chart.scaleService.getScaleConstructor('logarithmic');
var scale = new Constructor({
ctx: mockContext,
options: config,
data: mockData,
id: scaleID
});
scale.update(400, 400);
expect(scale.min).toBe(10);
expect(scale.max).toBe(1000);
});
it('Should ensure that the scale has a max and min that are not equal', function() {
var scaleID = 'myScale';
+90 -55
Ver Arquivo
@@ -58,10 +58,13 @@ describe('Test the radial linear scale', function() {
reverse: false,
showLabelBackdrop: true,
show: true,
template: "<%=value%>",
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
},
});
// Is this actually a function
expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
});
it('Should correctly determine the max & min data values', function() {
@@ -92,6 +95,38 @@ describe('Test the radial linear scale', function() {
expect(scale.max).toBe(200);
});
it('Should correctly determine the max & min data values when there are hidden datasets', function() {
var scaleID = 'myScale';
var mockData = {
datasets: [{
yAxisID: scaleID,
data: [10, 5, 0, -5, 78, -100]
}, {
yAxisID: scaleID,
data: [150]
}, {
yAxisID: scaleID,
data: [1000],
hidden: true
}],
labels: ['lablel1', 'label2', 'label3', 'label4', 'label5', 'label6']
};
var mockContext = window.createMockContext();
var Constructor = Chart.scaleService.getScaleConstructor('radialLinear');
var scale = new Constructor({
ctx: mockContext,
options: Chart.scaleService.getScaleDefaults('radialLinear'), // use default config for scale
data: mockData,
id: scaleID,
});
scale.update(200, 300);
expect(scale.min).toBe(-100);
expect(scale.max).toBe(200);
});
it('Should ensure that the scale has a max and min that are not equal', function() {
var scaleID = 'myScale';
@@ -240,7 +275,7 @@ describe('Test the radial linear scale', function() {
scale.bottom = 305;
scale.update(200, 300);
expect(scale.drawingArea).toBe(36);
expect(scale.drawingArea).toBe(37);
expect(scale.xCenter).toBe(110);
expect(scale.yCenter).toBe(155);
});
@@ -273,17 +308,17 @@ describe('Test the radial linear scale', function() {
scale.update(200, 300);
expect(scale.getDistanceFromCenterForValue(scale.min)).toBe(0);
expect(scale.getDistanceFromCenterForValue(scale.max)).toBe(36);
expect(scale.getDistanceFromCenterForValue(scale.max)).toBe(37);
expect(scale.getPointPositionForValue(1, 5)).toEqual({
x: 102.13987716166409,
y: 149.30471176265638,
x: 102,
y: 149,
});
config.reverse = true;
scale.update(200, 300);
expect(scale.getDistanceFromCenterForValue(scale.min)).toBe(36);
expect(scale.getDistanceFromCenterForValue(scale.min)).toBe(37);
expect(scale.getDistanceFromCenterForValue(scale.max)).toBe(0);
});
@@ -349,7 +384,7 @@ describe('Test the radial linear scale', function() {
"args": []
}, {
"name": "arc",
"args": [100, 150, 9, 0, 6.283185307179586]
"args": [100, 150, 9.25, 0, 6.283185307179586]
}, {
"name": "closePath",
"args": []
@@ -364,13 +399,13 @@ describe('Test the radial linear scale', function() {
"args": ["rgba(255,255,255,0.75)"]
}, {
"name": "fillRect",
"args": [88, 133, 24, 16]
"args": [88, 132.75, 24, 16]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["20", 100, 141]
"args": ["20", 100, 140.75]
}, {
"name": "setStrokeStyle",
"args": ["rgba(0, 0, 0, 0.1)"]
@@ -382,7 +417,7 @@ describe('Test the radial linear scale', function() {
"args": []
}, {
"name": "arc",
"args": [100, 150, 18, 0, 6.283185307179586]
"args": [100, 150, 18.5, 0, 6.283185307179586]
}, {
"name": "closePath",
"args": []
@@ -397,13 +432,13 @@ describe('Test the radial linear scale', function() {
"args": ["rgba(255,255,255,0.75)"]
}, {
"name": "fillRect",
"args": [88, 124, 24, 16]
"args": [88, 123.5, 24, 16]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["40", 100, 132]
"args": ["40", 100, 131.5]
}, {
"name": "setStrokeStyle",
"args": ["rgba(0, 0, 0, 0.1)"]
@@ -415,7 +450,7 @@ describe('Test the radial linear scale', function() {
"args": []
}, {
"name": "arc",
"args": [100, 150, 27, 0, 6.283185307179586]
"args": [100, 150, 27.75, 0, 6.283185307179586]
}, {
"name": "closePath",
"args": []
@@ -430,13 +465,13 @@ describe('Test the radial linear scale', function() {
"args": ["rgba(255,255,255,0.75)"]
}, {
"name": "fillRect",
"args": [88, 115, 24, 16]
"args": [88, 114.25, 24, 16]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["60", 100, 123]
"args": ["60", 100, 122.25]
}, {
"name": "setStrokeStyle",
"args": ["rgba(0, 0, 0, 0.1)"]
@@ -448,7 +483,7 @@ describe('Test the radial linear scale', function() {
"args": []
}, {
"name": "arc",
"args": [100, 150, 36, 0, 6.283185307179586]
"args": [100, 150, 37, 0, 6.283185307179586]
}, {
"name": "closePath",
"args": []
@@ -463,13 +498,13 @@ describe('Test the radial linear scale', function() {
"args": ["rgba(255,255,255,0.75)"]
}, {
"name": "fillRect",
"args": [88, 106, 24, 16]
"args": [88, 105, 24, 16]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["80", 100, 114]
"args": ["80", 100, 113]
}];
expect(mockContext.getCalls()).toEqual(expected);
@@ -491,16 +526,16 @@ describe('Test the radial linear scale', function() {
"args": [100, 141]
}, {
"name": "lineTo",
"args": [108.55950864665638, 147.21884705062547]
"args": [109, 147]
}, {
"name": "lineTo",
"args": [105.29006727063226, 157.28115294937453]
"args": [105, 157]
}, {
"name": "lineTo",
"args": [94.70993272936774, 157.28115294937453]
"args": [95, 157]
}, {
"name": "lineTo",
"args": [91.44049135334362, 147.21884705062547]
"args": [91, 147]
}, {
"name": "closePath",
"args": []
@@ -515,13 +550,13 @@ describe('Test the radial linear scale', function() {
"args": ["rgba(255,255,255,0.75)"]
}, {
"name": "fillRect",
"args": [88, 133, 24, 16]
"args": [88, 132.75, 24, 16]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["20", 100, 141]
"args": ["20", 100, 140.75]
}, {
"name": "setStrokeStyle",
"args": ["rgba(0, 0, 0, 0.1)"]
@@ -536,16 +571,16 @@ describe('Test the radial linear scale', function() {
"args": [100, 132]
}, {
"name": "lineTo",
"args": [117.11901729331277, 144.43769410125094]
"args": [118, 144]
}, {
"name": "lineTo",
"args": [110.58013454126451, 164.56230589874906]
"args": [111, 165]
}, {
"name": "lineTo",
"args": [89.41986545873549, 164.56230589874906]
"args": [89, 165]
}, {
"name": "lineTo",
"args": [82.88098270668723, 144.43769410125094]
"args": [82, 144]
}, {
"name": "closePath",
"args": []
@@ -560,13 +595,13 @@ describe('Test the radial linear scale', function() {
"args": ["rgba(255,255,255,0.75)"]
}, {
"name": "fillRect",
"args": [88, 124, 24, 16]
"args": [88, 123.5, 24, 16]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["40", 100, 132]
"args": ["40", 100, 131.5]
}, {
"name": "setStrokeStyle",
"args": ["rgba(0, 0, 0, 0.1)"]
@@ -578,19 +613,19 @@ describe('Test the radial linear scale', function() {
"args": []
}, {
"name": "moveTo",
"args": [100, 123]
"args": [100, 122]
}, {
"name": "lineTo",
"args": [125.67852593996915, 141.6565411518764]
"args": [126, 141]
}, {
"name": "lineTo",
"args": [115.87020181189678, 171.8434588481236]
"args": [116, 172]
}, {
"name": "lineTo",
"args": [84.12979818810322, 171.8434588481236]
"args": [84, 172]
}, {
"name": "lineTo",
"args": [74.32147406003085, 141.6565411518764]
"args": [74, 141]
}, {
"name": "closePath",
"args": []
@@ -605,13 +640,13 @@ describe('Test the radial linear scale', function() {
"args": ["rgba(255,255,255,0.75)"]
}, {
"name": "fillRect",
"args": [88, 115, 24, 16]
"args": [88, 114.25, 24, 16]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["60", 100, 123]
"args": ["60", 100, 122.25]
}, {
"name": "setStrokeStyle",
"args": ["rgba(0, 0, 0, 0.1)"]
@@ -623,19 +658,19 @@ describe('Test the radial linear scale', function() {
"args": []
}, {
"name": "moveTo",
"args": [100, 114]
"args": [100, 113]
}, {
"name": "lineTo",
"args": [134.23803458662553, 138.87538820250188]
"args": [135, 139]
}, {
"name": "lineTo",
"args": [121.16026908252903, 179.12461179749812]
"args": [122, 180]
}, {
"name": "lineTo",
"args": [78.83973091747097, 179.12461179749812]
"args": [78, 180]
}, {
"name": "lineTo",
"args": [65.76196541337447, 138.8753882025019]
"args": [65, 139]
}, {
"name": "closePath",
"args": []
@@ -650,13 +685,13 @@ describe('Test the radial linear scale', function() {
"args": ["rgba(255,255,255,0.75)"]
}, {
"name": "fillRect",
"args": [88, 106, 24, 16]
"args": [88, 105, 24, 16]
}, {
"name": "setFillStyle",
"args": ["#666"]
}, {
"name": "fillText",
"args": ["80", 100, 114]
"args": ["80", 100, 113]
}, {
"name": "setLineWidth",
"args": [1]
@@ -671,7 +706,7 @@ describe('Test the radial linear scale', function() {
"args": [100, 150]
}, {
"name": "lineTo",
"args": [65.76196541337447, 138.8753882025019]
"args": [65, 139]
}, {
"name": "stroke",
"args": []
@@ -683,7 +718,7 @@ describe('Test the radial linear scale', function() {
"args": ["#666"]
}, {
"name": "fillText",
"args": ["point5", 61.0066828318987, 137.33030323062715]
"args": ["point5", 60, 137]
}, {
"name": "beginPath",
"args": []
@@ -692,7 +727,7 @@ describe('Test the radial linear scale', function() {
"args": [100, 150]
}, {
"name": "lineTo",
"args": [78.83973091747097, 179.12461179749812]
"args": [78, 180]
}, {
"name": "stroke",
"args": []
@@ -704,7 +739,7 @@ describe('Test the radial linear scale', function() {
"args": ["#666"]
}, {
"name": "fillText",
"args": ["point4", 75.9008046560086, 183.16969676937285]
"args": ["point4", 75, 184]
}, {
"name": "beginPath",
"args": []
@@ -713,7 +748,7 @@ describe('Test the radial linear scale', function() {
"args": [100, 150]
}, {
"name": "lineTo",
"args": [121.16026908252903, 179.12461179749812]
"args": [122, 180]
}, {
"name": "stroke",
"args": []
@@ -725,7 +760,7 @@ describe('Test the radial linear scale', function() {
"args": ["#666"]
}, {
"name": "fillText",
"args": ["point3", 124.0991953439914, 183.16969676937285]
"args": ["point3", 125, 184]
}, {
"name": "beginPath",
"args": []
@@ -734,7 +769,7 @@ describe('Test the radial linear scale', function() {
"args": [100, 150]
}, {
"name": "lineTo",
"args": [134.23803458662553, 138.87538820250188]
"args": [135, 139]
}, {
"name": "stroke",
"args": []
@@ -746,7 +781,7 @@ describe('Test the radial linear scale', function() {
"args": ["#666"]
}, {
"name": "fillText",
"args": ["point2", 138.9933171681013, 137.33030323062715]
"args": ["point2", 140, 137]
}, {
"name": "beginPath",
"args": []
@@ -755,7 +790,7 @@ describe('Test the radial linear scale', function() {
"args": [100, 150]
}, {
"name": "lineTo",
"args": [100, 114]
"args": [100, 113]
}, {
"name": "stroke",
"args": []
@@ -767,7 +802,7 @@ describe('Test the radial linear scale', function() {
"args": ["#666"]
}, {
"name": "fillText",
"args": ["point1", 100, 109]
"args": ["point1", 100, 108]
}]);
});
});
});
+17 -6
Ver Arquivo
@@ -1,5 +1,10 @@
// Time scale tests
describe('Time scale tests', function() {
it('Should load moment.js as a dependency', function() {
expect(window.moment).not.toBe(undefined);
});
it('Should register the constructor with the scale service', function() {
var Constructor = Chart.scaleService.getScaleConstructor('time');
expect(Constructor).not.toBe(undefined);
@@ -41,7 +46,7 @@ describe('Time scale tests', function() {
padding: 10,
reverse: false,
show: true,
template: "<%=value%>"
callback: defaultConfig.ticks.callback, // make this nicer, then check explicitly below
},
time: {
format: false,
@@ -50,9 +55,12 @@ describe('Time scale tests', function() {
displayFormat: false,
}
});
// Is this actually a function
expect(defaultConfig.ticks.callback).toEqual(jasmine.any(Function));
});
it ('should build ticks using days', function() {
it('should build ticks using days', function() {
var scaleID = 'myScale';
var mockData = {
@@ -75,7 +83,7 @@ describe('Time scale tests', function() {
expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 2, 2015', 'Jan 3, 2015', 'Jan 4, 2015', 'Jan 5, 2015', 'Jan 6, 2015', 'Jan 7, 2015', 'Jan 8, 2015', 'Jan 9, 2015', 'Jan 10, 2015', 'Jan 11, 2015']);
});
it ('should build ticks using the config unit', function() {
it('should build ticks using the config unit', function() {
var scaleID = 'myScale';
var mockData = {
@@ -98,7 +106,7 @@ describe('Time scale tests', function() {
expect(scale.ticks).toEqual(['Jan 1, 8PM', 'Jan 1, 9PM', 'Jan 1, 10PM', 'Jan 1, 11PM', 'Jan 2, 12AM', 'Jan 2, 1AM', 'Jan 2, 2AM', 'Jan 2, 3AM', 'Jan 2, 4AM', 'Jan 2, 5AM', 'Jan 2, 6AM', 'Jan 2, 7AM', 'Jan 2, 8AM', 'Jan 2, 9AM', 'Jan 2, 10AM', 'Jan 2, 11AM', 'Jan 2, 12PM', 'Jan 2, 1PM', 'Jan 2, 2PM', 'Jan 2, 3PM', 'Jan 2, 4PM', 'Jan 2, 5PM', 'Jan 2, 6PM', 'Jan 2, 7PM', 'Jan 2, 8PM', 'Jan 2, 9PM']);
});
it ('should build ticks using the config diff', function() {
it('should build ticks using the config diff', function() {
var scaleID = 'myScale';
var mockData = {
@@ -122,11 +130,14 @@ describe('Time scale tests', function() {
expect(scale.ticks).toEqual(['Dec 28, 2014', 'Jan 4, 2015', 'Jan 11, 2015', 'Jan 18, 2015', 'Jan 25, 2015', 'Feb 1, 2015', 'Feb 8, 2015', 'Feb 15, 2015']);
});
it ('should get the correct pixel for a value', function() {
it('should get the correct pixel for a value', function() {
var scaleID = 'myScale';
var mockData = {
labels: ["2015-01-01T20:00:00", "2015-01-02T21:00:00", "2015-01-03T22:00:00", "2015-01-05T23:00:00", "2015-01-07T03:00", "2015-01-08T10:00", "2015-01-10T12:00"], // days
datasets: [{
data: [],
}]
};
var mockContext = window.createMockContext();
@@ -171,4 +182,4 @@ describe('Time scale tests', function() {
expect(verticalScale.getPixelForValue('', 0, 0)).toBe(6);
expect(verticalScale.getPixelForValue('', 6, 0)).toBe(394);
});
});
});