diff --git a/docs/00-Getting-Started.md b/docs/00-Getting-Started.md
index 9198861fe..c0b0284d3 100644
--- a/docs/00-Getting-Started.md
+++ b/docs/00-Getting-Started.md
@@ -158,8 +158,7 @@ xPadding | Number | 6 | Padding to add on top and bottom of tooltip
yPadding | Number | 6 | Padding to add on left and right of tooltip
caretSize | Number | 5 | Size, in px, of the tooltip arrow
cornerRadius | Number | 6 | Radius of tooltip corner curves
-xOffset | Number | 10 |
-multiKeyBackground | Color | "#fff" |
+multiKeyBackground | Color | "#fff" | Color to draw behind the colored boxes when multiple items are in the tooltip
| | |
callbacks | - | - | 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
**Callback Functions** | | | All functions are called with the same arguments
diff --git a/docs/01-Scales.md b/docs/01-Scales.md
index be4872dd0..428a911e8 100644
--- a/docs/01-Scales.md
+++ b/docs/01-Scales.md
@@ -153,16 +153,18 @@ The time scale extends the core scale class with the following tick template:
// Moment js for each of the units. Replaces `displayFormat`
// To override, use a pattern string from http://momentjs.com/docs/#/displaying/format/
displayFormats: {
- 'millisecond': 'SSS [ms]',
- 'second': 'h:mm:ss a', // 11:20:01 AM
- 'minute': 'h:mm:ss a', // 11:20:01 AM
- 'hour': 'MMM D, hA', // Sept 4, 5PM
- 'day': 'll', // Sep 4 2015
- 'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
- 'month': 'MMM YYYY', // Sept 2015
- 'quarter': '[Q]Q - YYYY', // Q3
- 'year': 'YYYY', // 2015
- },
+ 'millisecond': 'SSS [ms]',
+ 'second': 'h:mm:ss a', // 11:20:01 AM
+ 'minute': 'h:mm:ss a', // 11:20:01 AM
+ 'hour': 'MMM D, hA', // Sept 4, 5PM
+ 'day': 'll', // Sep 4 2015
+ 'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
+ 'month': 'MMM YYYY', // Sept 2015
+ 'quarter': '[Q]Q - YYYY', // Q3
+ 'year': 'YYYY', // 2015
+ },
+ // Sets the display format used in tooltip generation
+ tooltipFormat: ''
},
}
```
diff --git a/samples/combo-time-scale.html b/samples/combo-time-scale.html
deleted file mode 100644
index 939be9282..000000000
--- a/samples/combo-time-scale.html
+++ /dev/null
@@ -1,191 +0,0 @@
-
-
-
-
- Line Chart
-
-
-
-
-
-
-
-
-
-
-
-
- Randomize Data
- Add Dataset
- Remove Dataset
- Add Data
- Remove Data
-
-
-
-
-
diff --git a/samples/line-time-point-data.html b/samples/line-time-point-data.html
deleted file mode 100644
index 2d8077acf..000000000
--- a/samples/line-time-point-data.html
+++ /dev/null
@@ -1,164 +0,0 @@
-
-
-
-
- Time Scale Point Data
-
-
-
-
-
-
-
-
-
-
-
-
- Randomize Data
- Add Data
- Remove Data
-
-
-
-
-
diff --git a/samples/line-time-scale.html b/samples/line-time-scale.html
deleted file mode 100644
index ecde87573..000000000
--- a/samples/line-time-scale.html
+++ /dev/null
@@ -1,206 +0,0 @@
-
-
-
-
- Line Chart
-
-
-
-
-
-
-
-
-
-
-
-
- Randomize Data
- Add Dataset
- Remove Dataset
- Add Data
- Remove Data
-
-
-
-
-
diff --git a/samples/line.html b/samples/line.html
index 0647173b4..00c0f499f 100644
--- a/samples/line.html
+++ b/samples/line.html
@@ -88,7 +88,7 @@
}
},
hover: {
- mode: 'label'
+ mode: 'dataset'
},
scales: {
xAxes: [{
diff --git a/samples/timeScale/combo-time-scale.html b/samples/timeScale/combo-time-scale.html
new file mode 100644
index 000000000..590c2a90e
--- /dev/null
+++ b/samples/timeScale/combo-time-scale.html
@@ -0,0 +1,180 @@
+
+
+
+
+ Line Chart
+
+
+
+
+
+
+
+
+
+
+
+
+ Randomize Data
+ Add Dataset
+ Remove Dataset
+ Add Data
+ Remove Data
+
+
+
+
+
diff --git a/samples/timeScale/line-time-point-data.html b/samples/timeScale/line-time-point-data.html
new file mode 100644
index 000000000..d02805ecc
--- /dev/null
+++ b/samples/timeScale/line-time-point-data.html
@@ -0,0 +1,172 @@
+
+
+
+
+ Time Scale Point Data
+
+
+
+
+
+
+
+
+
+
+
+
+ Randomize Data
+ Add Data
+ Remove Data
+
+
+
+
+
diff --git a/samples/timeScale/line-time-scale.html b/samples/timeScale/line-time-scale.html
new file mode 100644
index 000000000..85cc9fde6
--- /dev/null
+++ b/samples/timeScale/line-time-scale.html
@@ -0,0 +1,211 @@
+
+
+
+
+ Line Chart
+
+
+
+
+
+
+
+
+
+
+
+
+ Randomize Data
+ Add Dataset
+ Remove Dataset
+ Add Data
+ Remove Data
+
+
+
+
+
diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js
index a1c631271..a97e284e0 100644
--- a/src/controllers/controller.bar.js
+++ b/src/controllers/controller.bar.js
@@ -233,9 +233,9 @@
var datasetCount = this.getBarCount();
var tickWidth = (function() {
- var min = xScale.getPixelForValue(null, 1) - xScale.getPixelForValue(null, 0);
+ var min = xScale.getPixelForTick(1) - xScale.getPixelForTick(0);
for (var i = 2; i < this.getDataset().data.length; i++) {
- min = Math.min(xScale.getPixelForValue(null, i) - xScale.getPixelForValue(null, i - 1), min);
+ min = Math.min(xScale.getPixelForTick(i) - xScale.getPixelForTick(i - 1), min);
}
return min;
}).call(this);
@@ -290,7 +290,7 @@
var barIndex = this.getBarIndex(datasetIndex);
var ruler = this.getRuler();
- var leftTick = xScale.getPixelForValue(null, index, barIndex, this.chart.isCombo);
+ var leftTick = xScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo);
leftTick -= this.chart.isCombo ? (ruler.tickWidth / 2) : 0;
if (xScale.options.stacked) {
diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js
index fddc97da1..2c37b9b90 100644
--- a/src/controllers/controller.doughnut.js
+++ b/src/controllers/controller.doughnut.js
@@ -207,9 +207,10 @@
x: centerX,
y: centerY,
startAngle: Math.PI * -0.5, // use - PI / 2 instead of 3PI / 2 to make animations better. It means that we never deal with overflow during the transition function
+ endAngle: Math.PI * -0.5,
circumference: (this.chart.options.animation.animateRotate) ? 0 : this.calculateCircumference(this.getDataset().data[index]),
outerRadius: (this.chart.options.animation.animateScale) ? 0 : this.outerRadius,
- innerRadius: (this.chart.options.animation.animateScale) ? 0 : this.innerRadius,
+ innerRadius: (this.chart.options.animation.animateScale) ? 0 : this.innerRadius
};
helpers.extend(arc, {
diff --git a/src/core/core.controller.js b/src/core/core.controller.js
index 88bf11a83..e9f1e87db 100644
--- a/src/core/core.controller.js
+++ b/src/core/core.controller.js
@@ -256,7 +256,7 @@
render: function render(duration, lazy) {
- if ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration == 'undefined' && this.options.animation.duration !== 0)) {
+ if (this.options.animation !== false && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration == 'undefined' && this.options.animation.duration !== 0))) {
var animation = new Chart.Animation();
animation.numSteps = (duration || this.options.animation.duration) / 16.66; //60 fps
animation.easing = this.options.animation.easing;
@@ -358,22 +358,13 @@
},
getDatasetAtEvent: function(e) {
- var eventPosition = helpers.getRelativePosition(e, this.chart);
- var elementsArray = [];
+ var elementsArray = this.getElementAtEvent(e);
- 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);
+ if (elementsArray.length > 0) {
+ elementsArray = this.data.datasets[elementsArray[0]._datasetIndex].metaData;
+ }
- return elementsArray.length ? elementsArray : [];
+ return elementsArray;
},
generateLegend: function generateLegend() {
diff --git a/src/core/core.scale.js b/src/core/core.scale.js
index 0a19d9468..a4f0ca5ae 100644
--- a/src/core/core.scale.js
+++ b/src/core/core.scale.js
@@ -343,7 +343,11 @@
}
// If it is in fact an object, dive in one more level
if (typeof(rawValue) === "object") {
- return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
+ if (rawValue instanceof Date) {
+ return rawValue;
+ } else {
+ return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
+ }
}
// Value is good, return it
diff --git a/src/core/core.tooltip.js b/src/core/core.tooltip.js
index 164a0a8bb..cbc3111b0 100644
--- a/src/core/core.tooltip.js
+++ b/src/core/core.tooltip.js
@@ -35,7 +35,6 @@
xPadding: 6,
caretSize: 5,
cornerRadius: 6,
- xOffset: 10,
multiKeyBackground: '#fff',
callbacks: {
// Args are: (tooltipItems, data)
@@ -98,7 +97,6 @@
// Positioning
xPadding: options.tooltips.xPadding,
yPadding: options.tooltips.yPadding,
- xOffset: options.tooltips.xOffset,
// Body
bodyColor: options.tooltips.bodyColor,
@@ -153,7 +151,7 @@
// Args are: (tooltipItem, data)
getBeforeBody: function() {
- var lines = this._options.tooltips.callbacks.beforeBody.call(this, arguments);
+ var lines = this._options.tooltips.callbacks.beforeBody.apply(this, arguments);
return helpers.isArray(lines) ? lines : [lines];
},
@@ -174,7 +172,7 @@
// Args are: (tooltipItem, data)
getAfterBody: function() {
- var lines = this._options.tooltips.callbacks.afterBody.call(this, arguments);
+ var lines = this._options.tooltips.callbacks.afterBody.apply(this, arguments);
return helpers.isArray(lines) ? lines : [lines];
},
@@ -224,10 +222,7 @@
},
update: function(changed) {
-
- var ctx = this._chart.ctx;
-
- if(this._active.length){
+ if (this._active.length){
this._model.opacity = 1;
var element = this._active[0],
@@ -236,7 +231,7 @@
var tooltipItems = [];
- if (this._options.tooltips.mode == 'single') {
+ if (this._options.tooltips.mode === 'single') {
var yScale = element._yScale || element._scale; // handle radar || polarArea charts
tooltipItems.push({
xLabel: element._xScale ? element._xScale.getLabelForIndex(element._index, element._datasetIndex) : '',
@@ -263,7 +258,7 @@
}
});
- helpers.each(this._active, function(active, i) {
+ helpers.each(this._active, function(active) {
if (active) {
labelColors.push({
borderColor: active._view.borderColor,
@@ -336,15 +331,15 @@
// Width
var tooltipWidth = 0;
- helpers.each(vm.title, function(line, i) {
+ helpers.each(vm.title, function(line) {
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) {
+ helpers.each(vm.body, function(line) {
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));
+ 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) {
+ helpers.each(vm.footer, function(line) {
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
});
@@ -374,17 +369,17 @@
var tooltipX = vm.x,
tooltipY = vm.y;
- if (vm.yAlign == 'top') {
+ if (vm.yAlign === 'top') {
tooltipY = vm.y - vm.caretSize - vm.cornerRadius;
- } else if (vm.yAlign == 'bottom') {
+ } else if (vm.yAlign === 'bottom') {
tooltipY = vm.y - tooltipHeight + vm.caretSize + vm.cornerRadius;
} else {
tooltipY = vm.y - (tooltipHeight / 2);
}
- if (vm.xAlign == 'left') {
+ if (vm.xAlign === 'left') {
tooltipX = vm.x - tooltipTotalWidth;
- } else if (vm.xAlign == 'right') {
+ } else if (vm.xAlign === 'right') {
tooltipX = vm.x + caretPadding + vm.caretSize;
} else {
tooltipX = vm.x + (tooltipTotalWidth / 2);
@@ -406,7 +401,7 @@
if (this._options.tooltips.enabled) {
ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
- if (vm.xAlign == 'left') {
+ if (vm.xAlign === 'left') {
ctx.beginPath();
ctx.moveTo(vm.x - caretPadding, vm.y);
@@ -442,7 +437,7 @@
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) {
+ if (i + 1 === vm.title.length) {
yBase += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing
}
}, this);
@@ -456,8 +451,8 @@
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);
+ helpers.each(vm.beforeBody, function(beforeBody) {
+ ctx.fillText(beforeBody, xBase, yBase);
yBase += vm.bodyFontSize + vm.bodySpacing;
});
@@ -465,9 +460,9 @@
// Draw Legend-like boxes if needed
- if (this._options.tooltips.mode != 'single') {
+ if (this._options.tooltips.mode !== 'single') {
// Fill a white rect so that colours merge nicely if the opacity is < 1
- ctx.fillStyle = helpers.color('#FFFFFF').alpha(opacity).rgbaString();
+ ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString();
ctx.fillRect(xBase, yBase, vm.bodyFontSize, vm.bodyFontSize);
// Border
@@ -482,15 +477,15 @@
}
// Body Line
- ctx.fillText(body, xBase + (this._options.tooltips.mode != 'single' ? (vm.bodyFontSize + 2) : 0), yBase);
+ 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);
+ helpers.each(vm.afterBody, function(afterBody) {
+ ctx.fillText(afterBody, xBase, yBase);
yBase += vm.bodyFontSize;
});
@@ -507,7 +502,7 @@
ctx.fillStyle = helpers.color(vm.footerColor).alpha(opacity).rgbString();
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
- helpers.each(vm.footer, function(footer, i) {
+ helpers.each(vm.footer, function(footer) {
ctx.fillText(footer, xBase, yBase);
yBase += vm.footerFontSize + vm.footerSpacing;
}, this);
diff --git a/src/elements/element.line.js b/src/elements/element.line.js
index 805da8c51..2ba31eadb 100644
--- a/src/elements/element.line.js
+++ b/src/elements/element.line.js
@@ -110,7 +110,7 @@
ctx.lineTo(previousPoint._view.x, this._view.scaleZero);
ctx.moveTo(nextPoint._view.x, this._view.scaleZero);
}
- }, function(previousPoint, point, nextPoint) {
+ }, function(previousPoint, point) {
// If we skipped the last point, draw a line to ourselves so that the fill is nice
ctx.lineTo(point._view.x, point._view.y);
});
@@ -154,7 +154,7 @@
} else {
this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
ctx.moveTo(nextPoint._view.x, nextPoint._view.y);
- }, function(previousPoint, point, nextPoint) {
+ }, function(previousPoint, point) {
// If we skipped the last point, move up to our point preventing a line from being drawn
ctx.moveTo(point._view.x, point._view.y);
});
diff --git a/src/scales/scale.time.js b/src/scales/scale.time.js
index 7c132d306..8c957beb0 100644
--- a/src/scales/scale.time.js
+++ b/src/scales/scale.time.js
@@ -164,9 +164,9 @@
if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.tickRange / labelCapacity) < helpers.max(unitDefinition.steps)) {
// Use one of the prefedined steps
- for (var idx = 1; idx < unitDefinition.steps.length; ++idx) {
+ for (var idx = 0; idx < unitDefinition.steps.length; ++idx) {
if (unitDefinition.steps[idx] > Math.ceil(this.tickRange / labelCapacity)) {
- this.unitScale = unitDefinition.steps[idx - 1];
+ this.unitScale = unitDefinition.steps[idx];
break;
}
}
@@ -224,11 +224,16 @@
label = this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
}
+ // Format nicely
+ if (this.options.time.tooltipFormat) {
+ label = this.parseTime(label).format(this.options.time.tooltipFormat);
+ }
+
return label;
},
convertTicksToLabels: function() {
this.ticks = this.ticks.map(function(tick, index, ticks) {
- var formattedTick = tick.format(this.options.time.displayFormat ? this.options.time.displayFormat : this.options.time.displayFormats[this.tickUnit]);
+ var formattedTick = tick.format(this.displayFormat);
if (this.options.ticks.userCallback) {
return this.options.ticks.userCallback(formattedTick, index, ticks);
@@ -250,7 +255,6 @@
return this.left + Math.round(valueOffset);
} else {
- //return this.top + (decimal * (this.height / this.ticks.length));
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
var valueHeight = innerHeight / Math.max(this.ticks.length - 1, 1);
var heightOffset = (innerHeight * decimal) + this.paddingTop;
diff --git a/test/controller.doughnut.tests.js b/test/controller.doughnut.tests.js
index 34ecd1949..7328b48af 100644
--- a/test/controller.doughnut.tests.js
+++ b/test/controller.doughnut.tests.js
@@ -105,36 +105,40 @@ describe('Doughnut controller tests', function() {
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
+ endAngle: Math.PI * -0.5,
circumference: 2.166614539857563,
outerRadius: 49,
- innerRadius: 36.75,
+ innerRadius: 36.75
});
expect(chart.data.datasets[1].metaData[1]._model).toEqual({
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
+ endAngle: Math.PI * -0.5,
circumference: 3.2499218097863447,
outerRadius: 49,
- innerRadius: 36.75,
+ innerRadius: 36.75
});
expect(chart.data.datasets[1].metaData[2]._model).toEqual({
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
+ endAngle: Math.PI * -0.5,
circumference: 0,
outerRadius: 49,
- innerRadius: 36.75,
+ innerRadius: 36.75
});
expect(chart.data.datasets[1].metaData[3]._model).toEqual({
x: 50,
y: 100,
startAngle: Math.PI * -0.5,
+ endAngle: Math.PI * -0.5,
circumference: 0.8666458159430251,
outerRadius: 49,
- innerRadius: 36.75,
+ innerRadius: 36.75
});
controller.update();
diff --git a/test/scale.time.tests.js b/test/scale.time.tests.js
index a8a6c1a27..c67b92908 100644
--- a/test/scale.time.tests.js
+++ b/test/scale.time.tests.js
@@ -92,7 +92,35 @@ describe('Time scale tests', function() {
scale.update(400, 50);
// Counts down because the lines are drawn top to bottom
- 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']);
+ expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015', 'Jan 7, 2015', 'Jan 9, 2015', 'Jan 11, 2015']);
+ });
+
+ it('should build ticks using date objects', function() {
+ // Helper to build date objects
+ function newDateFromRef(days) {
+ return moment('01/01/2015 12:00', 'DD/MM/YYYY HH:mm').add(days, 'd').toDate();
+ }
+
+ var scaleID = 'myScale';
+ var mockData = {
+ labels: [newDateFromRef(0), newDateFromRef(1), newDateFromRef(2), newDateFromRef(4), newDateFromRef(6), newDateFromRef(7), newDateFromRef(9)], // days
+ };
+
+ var mockContext = window.createMockContext();
+ var Constructor = Chart.scaleService.getScaleConstructor('time');
+ var scale = new Constructor({
+ ctx: mockContext,
+ options: Chart.scaleService.getScaleDefaults('time'), // use default config for scale
+ chart: {
+ data: mockData
+ },
+ id: scaleID
+ });
+
+ scale.update(400, 50);
+
+ // Counts down because the lines are drawn top to bottom
+ expect(scale.ticks).toEqual(['Jan 1, 2015', 'Jan 3, 2015', 'Jan 5, 2015', 'Jan 7, 2015', 'Jan 9, 2015', 'Jan 11, 2015', 'Jan 13, 2015']);
});
it('should build ticks using the config unit', function() {