mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Make Chart.Animation/animations/Tooltip importable (#5382)
This commit is contained in:
parent
9fbac88938
commit
d284686452
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"indent-style": "tabs",
|
"indent-style": "tabs",
|
||||||
|
"line-end-style": false,
|
||||||
"attr-quote-style": "double",
|
"attr-quote-style": "double",
|
||||||
"spec-char-escape": false,
|
"spec-char-escape": false,
|
||||||
"attr-bans": [
|
"attr-bans": [
|
||||||
|
|||||||
@ -8,6 +8,8 @@ Chart.helpers = require('./helpers/index');
|
|||||||
// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
|
// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
|
||||||
require('./core/core.helpers')(Chart);
|
require('./core/core.helpers')(Chart);
|
||||||
|
|
||||||
|
Chart.Animation = require('./core/core.animation');
|
||||||
|
Chart.animationService = require('./core/core.animations');
|
||||||
Chart.defaults = require('./core/core.defaults');
|
Chart.defaults = require('./core/core.defaults');
|
||||||
Chart.Element = require('./core/core.element');
|
Chart.Element = require('./core/core.element');
|
||||||
Chart.elements = require('./elements/index');
|
Chart.elements = require('./elements/index');
|
||||||
@ -16,13 +18,12 @@ Chart.layouts = require('./core/core.layouts');
|
|||||||
Chart.platform = require('./platforms/platform');
|
Chart.platform = require('./platforms/platform');
|
||||||
Chart.plugins = require('./core/core.plugins');
|
Chart.plugins = require('./core/core.plugins');
|
||||||
Chart.Ticks = require('./core/core.ticks');
|
Chart.Ticks = require('./core/core.ticks');
|
||||||
|
Chart.Tooltip = require('./core/core.tooltip');
|
||||||
|
|
||||||
require('./core/core.animation')(Chart);
|
|
||||||
require('./core/core.controller')(Chart);
|
require('./core/core.controller')(Chart);
|
||||||
require('./core/core.datasetController')(Chart);
|
require('./core/core.datasetController')(Chart);
|
||||||
require('./core/core.scaleService')(Chart);
|
require('./core/core.scaleService')(Chart);
|
||||||
require('./core/core.scale')(Chart);
|
require('./core/core.scale')(Chart);
|
||||||
require('./core/core.tooltip')(Chart);
|
|
||||||
|
|
||||||
require('./scales/scale.linearbase')(Chart);
|
require('./scales/scale.linearbase')(Chart);
|
||||||
require('./scales/scale.category')(Chart);
|
require('./scales/scale.category')(Chart);
|
||||||
|
|||||||
@ -1,22 +1,8 @@
|
|||||||
/* global window: false */
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var defaults = require('./core.defaults');
|
|
||||||
var Element = require('./core.element');
|
var Element = require('./core.element');
|
||||||
var helpers = require('../helpers/index');
|
|
||||||
|
|
||||||
defaults._set('global', {
|
var exports = module.exports = Element.extend({
|
||||||
animation: {
|
|
||||||
duration: 1000,
|
|
||||||
easing: 'easeOutQuart',
|
|
||||||
onProgress: helpers.noop,
|
|
||||||
onComplete: helpers.noop
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = function(Chart) {
|
|
||||||
|
|
||||||
Chart.Animation = Element.extend({
|
|
||||||
chart: null, // the animation associated chart instance
|
chart: null, // the animation associated chart instance
|
||||||
currentStep: 0, // the current animation step
|
currentStep: 0, // the current animation step
|
||||||
numSteps: 60, // default number of steps
|
numSteps: 60, // default number of steps
|
||||||
@ -25,148 +11,33 @@ module.exports = function(Chart) {
|
|||||||
|
|
||||||
onAnimationProgress: null, // user specified callback to fire on each step of the animation
|
onAnimationProgress: null, // user specified callback to fire on each step of the animation
|
||||||
onAnimationComplete: null, // user specified callback to fire when the animation finishes
|
onAnimationComplete: null, // user specified callback to fire when the animation finishes
|
||||||
});
|
});
|
||||||
|
|
||||||
Chart.animationService = {
|
// DEPRECATIONS
|
||||||
frameDuration: 17,
|
|
||||||
animations: [],
|
|
||||||
dropFrames: 0,
|
|
||||||
request: null,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Chart} chart - The chart to animate.
|
|
||||||
* @param {Chart.Animation} animation - The animation that we will animate.
|
|
||||||
* @param {Number} duration - The animation duration in ms.
|
|
||||||
* @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
|
|
||||||
*/
|
|
||||||
addAnimation: function(chart, animation, duration, lazy) {
|
|
||||||
var animations = this.animations;
|
|
||||||
var i, ilen;
|
|
||||||
|
|
||||||
animation.chart = chart;
|
|
||||||
|
|
||||||
if (!lazy) {
|
|
||||||
chart.animating = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, ilen = animations.length; i < ilen; ++i) {
|
|
||||||
if (animations[i].chart === chart) {
|
|
||||||
animations[i] = animation;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
animations.push(animation);
|
|
||||||
|
|
||||||
// If there are no animations queued, manually kickstart a digest, for lack of a better word
|
|
||||||
if (animations.length === 1) {
|
|
||||||
this.requestAnimationFrame();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
cancelAnimation: function(chart) {
|
|
||||||
var index = helpers.findIndex(this.animations, function(animation) {
|
|
||||||
return animation.chart === chart;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (index !== -1) {
|
|
||||||
this.animations.splice(index, 1);
|
|
||||||
chart.animating = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
requestAnimationFrame: function() {
|
|
||||||
var me = this;
|
|
||||||
if (me.request === null) {
|
|
||||||
// Skip animation frame requests until the active one is executed.
|
|
||||||
// This can happen when processing mouse events, e.g. 'mousemove'
|
|
||||||
// and 'mouseout' events will trigger multiple renders.
|
|
||||||
me.request = helpers.requestAnimFrame.call(window, function() {
|
|
||||||
me.request = null;
|
|
||||||
me.startDigest();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
startDigest: function() {
|
|
||||||
var me = this;
|
|
||||||
var startTime = Date.now();
|
|
||||||
var framesToDrop = 0;
|
|
||||||
|
|
||||||
if (me.dropFrames > 1) {
|
|
||||||
framesToDrop = Math.floor(me.dropFrames);
|
|
||||||
me.dropFrames = me.dropFrames % 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
me.advance(1 + framesToDrop);
|
|
||||||
|
|
||||||
var endTime = Date.now();
|
|
||||||
|
|
||||||
me.dropFrames += (endTime - startTime) / me.frameDuration;
|
|
||||||
|
|
||||||
// Do we have more stuff to animate?
|
|
||||||
if (me.animations.length > 0) {
|
|
||||||
me.requestAnimationFrame();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
advance: function(count) {
|
|
||||||
var animations = this.animations;
|
|
||||||
var animation, chart;
|
|
||||||
var i = 0;
|
|
||||||
|
|
||||||
while (i < animations.length) {
|
|
||||||
animation = animations[i];
|
|
||||||
chart = animation.chart;
|
|
||||||
|
|
||||||
animation.currentStep = (animation.currentStep || 0) + count;
|
|
||||||
animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
|
|
||||||
|
|
||||||
helpers.callback(animation.render, [chart, animation], chart);
|
|
||||||
helpers.callback(animation.onAnimationProgress, [animation], chart);
|
|
||||||
|
|
||||||
if (animation.currentStep >= animation.numSteps) {
|
|
||||||
helpers.callback(animation.onAnimationComplete, [animation], chart);
|
|
||||||
chart.animating = false;
|
|
||||||
animations.splice(i, 1);
|
|
||||||
} else {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provided for backward compatibility, use Chart.Animation instead
|
* Provided for backward compatibility, use Chart.Animation instead
|
||||||
* @prop Chart.Animation#animationObject
|
* @prop Chart.Animation#animationObject
|
||||||
* @deprecated since version 2.6.0
|
* @deprecated since version 2.6.0
|
||||||
* @todo remove at version 3
|
* @todo remove at version 3
|
||||||
*/
|
*/
|
||||||
Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
|
Object.defineProperty(exports.prototype, 'animationObject', {
|
||||||
get: function() {
|
get: function() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provided for backward compatibility, use Chart.Animation#chart instead
|
* Provided for backward compatibility, use Chart.Animation#chart instead
|
||||||
* @prop Chart.Animation#chartInstance
|
* @prop Chart.Animation#chartInstance
|
||||||
* @deprecated since version 2.6.0
|
* @deprecated since version 2.6.0
|
||||||
* @todo remove at version 3
|
* @todo remove at version 3
|
||||||
*/
|
*/
|
||||||
Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
|
Object.defineProperty(exports.prototype, 'chartInstance', {
|
||||||
get: function() {
|
get: function() {
|
||||||
return this.chart;
|
return this.chart;
|
||||||
},
|
},
|
||||||
set: function(value) {
|
set: function(value) {
|
||||||
this.chart = value;
|
this.chart = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
|
||||||
|
|||||||
129
src/core/core.animations.js
Normal file
129
src/core/core.animations.js
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/* global window: false */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var defaults = require('./core.defaults');
|
||||||
|
var helpers = require('../helpers/index');
|
||||||
|
|
||||||
|
defaults._set('global', {
|
||||||
|
animation: {
|
||||||
|
duration: 1000,
|
||||||
|
easing: 'easeOutQuart',
|
||||||
|
onProgress: helpers.noop,
|
||||||
|
onComplete: helpers.noop
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
frameDuration: 17,
|
||||||
|
animations: [],
|
||||||
|
dropFrames: 0,
|
||||||
|
request: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Chart} chart - The chart to animate.
|
||||||
|
* @param {Chart.Animation} animation - The animation that we will animate.
|
||||||
|
* @param {Number} duration - The animation duration in ms.
|
||||||
|
* @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
|
||||||
|
*/
|
||||||
|
addAnimation: function(chart, animation, duration, lazy) {
|
||||||
|
var animations = this.animations;
|
||||||
|
var i, ilen;
|
||||||
|
|
||||||
|
animation.chart = chart;
|
||||||
|
|
||||||
|
if (!lazy) {
|
||||||
|
chart.animating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, ilen = animations.length; i < ilen; ++i) {
|
||||||
|
if (animations[i].chart === chart) {
|
||||||
|
animations[i] = animation;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
animations.push(animation);
|
||||||
|
|
||||||
|
// If there are no animations queued, manually kickstart a digest, for lack of a better word
|
||||||
|
if (animations.length === 1) {
|
||||||
|
this.requestAnimationFrame();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelAnimation: function(chart) {
|
||||||
|
var index = helpers.findIndex(this.animations, function(animation) {
|
||||||
|
return animation.chart === chart;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
this.animations.splice(index, 1);
|
||||||
|
chart.animating = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
requestAnimationFrame: function() {
|
||||||
|
var me = this;
|
||||||
|
if (me.request === null) {
|
||||||
|
// Skip animation frame requests until the active one is executed.
|
||||||
|
// This can happen when processing mouse events, e.g. 'mousemove'
|
||||||
|
// and 'mouseout' events will trigger multiple renders.
|
||||||
|
me.request = helpers.requestAnimFrame.call(window, function() {
|
||||||
|
me.request = null;
|
||||||
|
me.startDigest();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
startDigest: function() {
|
||||||
|
var me = this;
|
||||||
|
var startTime = Date.now();
|
||||||
|
var framesToDrop = 0;
|
||||||
|
|
||||||
|
if (me.dropFrames > 1) {
|
||||||
|
framesToDrop = Math.floor(me.dropFrames);
|
||||||
|
me.dropFrames = me.dropFrames % 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
me.advance(1 + framesToDrop);
|
||||||
|
|
||||||
|
var endTime = Date.now();
|
||||||
|
|
||||||
|
me.dropFrames += (endTime - startTime) / me.frameDuration;
|
||||||
|
|
||||||
|
// Do we have more stuff to animate?
|
||||||
|
if (me.animations.length > 0) {
|
||||||
|
me.requestAnimationFrame();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
advance: function(count) {
|
||||||
|
var animations = this.animations;
|
||||||
|
var animation, chart;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
while (i < animations.length) {
|
||||||
|
animation = animations[i];
|
||||||
|
chart = animation.chart;
|
||||||
|
|
||||||
|
animation.currentStep = (animation.currentStep || 0) + count;
|
||||||
|
animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
|
||||||
|
|
||||||
|
helpers.callback(animation.render, [chart, animation], chart);
|
||||||
|
helpers.callback(animation.onAnimationProgress, [animation], chart);
|
||||||
|
|
||||||
|
if (animation.currentStep >= animation.numSteps) {
|
||||||
|
helpers.callback(animation.onAnimationComplete, [animation], chart);
|
||||||
|
chart.animating = false;
|
||||||
|
animations.splice(i, 1);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,11 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var Animation = require('./core.animation');
|
||||||
|
var animations = require('./core.animations');
|
||||||
var defaults = require('./core.defaults');
|
var defaults = require('./core.defaults');
|
||||||
var helpers = require('../helpers/index');
|
var helpers = require('../helpers/index');
|
||||||
var Interaction = require('./core.interaction');
|
var Interaction = require('./core.interaction');
|
||||||
var layouts = require('./core.layouts');
|
var layouts = require('./core.layouts');
|
||||||
var platform = require('../platforms/platform');
|
var platform = require('../platforms/platform');
|
||||||
var plugins = require('./core.plugins');
|
var plugins = require('./core.plugins');
|
||||||
|
var Tooltip = require('./core.tooltip');
|
||||||
|
|
||||||
module.exports = function(Chart) {
|
module.exports = function(Chart) {
|
||||||
|
|
||||||
@ -164,7 +167,7 @@ module.exports = function(Chart) {
|
|||||||
|
|
||||||
stop: function() {
|
stop: function() {
|
||||||
// Stops any current animation loop occurring
|
// Stops any current animation loop occurring
|
||||||
Chart.animationService.cancelAnimation(this);
|
animations.cancelAnimation(this);
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -519,7 +522,7 @@ module.exports = function(Chart) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
|
if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
|
||||||
var animation = new Chart.Animation({
|
var animation = new Animation({
|
||||||
numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
|
numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
|
||||||
easing: config.easing || animationOptions.easing,
|
easing: config.easing || animationOptions.easing,
|
||||||
|
|
||||||
@ -535,12 +538,12 @@ module.exports = function(Chart) {
|
|||||||
onAnimationComplete: onComplete
|
onAnimationComplete: onComplete
|
||||||
});
|
});
|
||||||
|
|
||||||
Chart.animationService.addAnimation(me, animation, duration, lazy);
|
animations.addAnimation(me, animation, duration, lazy);
|
||||||
} else {
|
} else {
|
||||||
me.draw();
|
me.draw();
|
||||||
|
|
||||||
// See https://github.com/chartjs/Chart.js/issues/3781
|
// See https://github.com/chartjs/Chart.js/issues/3781
|
||||||
onComplete(new Chart.Animation({numSteps: 0, chart: me}));
|
onComplete(new Animation({numSteps: 0, chart: me}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return me;
|
return me;
|
||||||
@ -775,7 +778,7 @@ module.exports = function(Chart) {
|
|||||||
|
|
||||||
initToolTip: function() {
|
initToolTip: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
me.tooltip = new Chart.Tooltip({
|
me.tooltip = new Tooltip({
|
||||||
_chart: me,
|
_chart: me,
|
||||||
_chartInstance: me, // deprecated, backward compatibility
|
_chartInstance: me, // deprecated, backward compatibility
|
||||||
_data: me.data,
|
_data: me.data,
|
||||||
|
|||||||
@ -96,18 +96,88 @@ defaults._set('global', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = function(Chart) {
|
var positioners = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to merge the opacity into a color
|
* Average mode places the tooltip at the average position of the elements shown
|
||||||
|
* @function Chart.Tooltip.positioners.average
|
||||||
|
* @param elements {ChartElement[]} the elements being displayed in the tooltip
|
||||||
|
* @returns {Point} tooltip position
|
||||||
*/
|
*/
|
||||||
function mergeOpacity(colorString, opacity) {
|
average: function(elements) {
|
||||||
var color = helpers.color(colorString);
|
if (!elements.length) {
|
||||||
return color.alpha(opacity * color.alpha()).rgbaString();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to push or concat based on if the 2nd parameter is an array or not
|
var i, len;
|
||||||
function pushOrConcat(base, toPush) {
|
var x = 0;
|
||||||
|
var y = 0;
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
for (i = 0, len = elements.length; i < len; ++i) {
|
||||||
|
var el = elements[i];
|
||||||
|
if (el && el.hasValue()) {
|
||||||
|
var pos = el.tooltipPosition();
|
||||||
|
x += pos.x;
|
||||||
|
y += pos.y;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: Math.round(x / count),
|
||||||
|
y: Math.round(y / count)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the tooltip position nearest of the item nearest to the event position
|
||||||
|
* @function Chart.Tooltip.positioners.nearest
|
||||||
|
* @param elements {Chart.Element[]} the tooltip elements
|
||||||
|
* @param eventPosition {Point} the position of the event in canvas coordinates
|
||||||
|
* @returns {Point} the tooltip position
|
||||||
|
*/
|
||||||
|
nearest: function(elements, eventPosition) {
|
||||||
|
var x = eventPosition.x;
|
||||||
|
var y = eventPosition.y;
|
||||||
|
var minDistance = Number.POSITIVE_INFINITY;
|
||||||
|
var i, len, nearestElement;
|
||||||
|
|
||||||
|
for (i = 0, len = elements.length; i < len; ++i) {
|
||||||
|
var el = elements[i];
|
||||||
|
if (el && el.hasValue()) {
|
||||||
|
var center = el.getCenterPoint();
|
||||||
|
var d = helpers.distanceBetweenPoints(eventPosition, center);
|
||||||
|
|
||||||
|
if (d < minDistance) {
|
||||||
|
minDistance = d;
|
||||||
|
nearestElement = el;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearestElement) {
|
||||||
|
var tp = nearestElement.tooltipPosition();
|
||||||
|
x = tp.x;
|
||||||
|
y = tp.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: x,
|
||||||
|
y: y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to merge the opacity into a color
|
||||||
|
*/
|
||||||
|
function mergeOpacity(colorString, opacity) {
|
||||||
|
var color = helpers.color(colorString);
|
||||||
|
return color.alpha(opacity * color.alpha()).rgbaString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to push or concat based on if the 2nd parameter is an array or not
|
||||||
|
function pushOrConcat(base, toPush) {
|
||||||
if (toPush) {
|
if (toPush) {
|
||||||
if (helpers.isArray(toPush)) {
|
if (helpers.isArray(toPush)) {
|
||||||
// base = base.concat(toPush);
|
// base = base.concat(toPush);
|
||||||
@ -118,12 +188,12 @@ module.exports = function(Chart) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private helper to create a tooltip item model
|
// Private helper to create a tooltip item model
|
||||||
// @param element : the chart element (point, arc, bar) to create the tooltip item for
|
// @param element : the chart element (point, arc, bar) to create the tooltip item for
|
||||||
// @return : new tooltip item
|
// @return : new tooltip item
|
||||||
function createTooltipItem(element) {
|
function createTooltipItem(element) {
|
||||||
var xScale = element._xScale;
|
var xScale = element._xScale;
|
||||||
var yScale = element._yScale || element._scale; // handle radar || polarArea charts
|
var yScale = element._yScale || element._scale; // handle radar || polarArea charts
|
||||||
var index = element._index;
|
var index = element._index;
|
||||||
@ -137,13 +207,13 @@ module.exports = function(Chart) {
|
|||||||
x: element._model.x,
|
x: element._model.x,
|
||||||
y: element._model.y
|
y: element._model.y
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to get the reset model for the tooltip
|
* Helper to get the reset model for the tooltip
|
||||||
* @param tooltipOpts {Object} the tooltip options
|
* @param tooltipOpts {Object} the tooltip options
|
||||||
*/
|
*/
|
||||||
function getBaseModel(tooltipOpts) {
|
function getBaseModel(tooltipOpts) {
|
||||||
var globalDefaults = defaults.global;
|
var globalDefaults = defaults.global;
|
||||||
var valueOrDefault = helpers.valueOrDefault;
|
var valueOrDefault = helpers.valueOrDefault;
|
||||||
|
|
||||||
@ -190,12 +260,12 @@ module.exports = function(Chart) {
|
|||||||
borderColor: tooltipOpts.borderColor,
|
borderColor: tooltipOpts.borderColor,
|
||||||
borderWidth: tooltipOpts.borderWidth
|
borderWidth: tooltipOpts.borderWidth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size of the tooltip
|
* Get the size of the tooltip
|
||||||
*/
|
*/
|
||||||
function getTooltipSize(tooltip, model) {
|
function getTooltipSize(tooltip, model) {
|
||||||
var ctx = tooltip._chart.ctx;
|
var ctx = tooltip._chart.ctx;
|
||||||
|
|
||||||
var height = model.yPadding * 2; // Tooltip Padding
|
var height = model.yPadding * 2; // Tooltip Padding
|
||||||
@ -258,12 +328,12 @@ module.exports = function(Chart) {
|
|||||||
width: width,
|
width: width,
|
||||||
height: height
|
height: height
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to get the alignment of a tooltip given the size
|
* Helper to get the alignment of a tooltip given the size
|
||||||
*/
|
*/
|
||||||
function determineAlignment(tooltip, size) {
|
function determineAlignment(tooltip, size) {
|
||||||
var model = tooltip._model;
|
var model = tooltip._model;
|
||||||
var chart = tooltip._chart;
|
var chart = tooltip._chart;
|
||||||
var chartArea = tooltip._chart.chartArea;
|
var chartArea = tooltip._chart.chartArea;
|
||||||
@ -331,12 +401,12 @@ module.exports = function(Chart) {
|
|||||||
xAlign: opts.xAlign ? opts.xAlign : xAlign,
|
xAlign: opts.xAlign ? opts.xAlign : xAlign,
|
||||||
yAlign: opts.yAlign ? opts.yAlign : yAlign
|
yAlign: opts.yAlign ? opts.yAlign : yAlign
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
|
* @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
|
||||||
*/
|
*/
|
||||||
function getBackgroundPoint(vm, size, alignment, chart) {
|
function getBackgroundPoint(vm, size, alignment, chart) {
|
||||||
// Background Position
|
// Background Position
|
||||||
var x = vm.x;
|
var x = vm.x;
|
||||||
var y = vm.y;
|
var y = vm.y;
|
||||||
@ -385,9 +455,9 @@ module.exports = function(Chart) {
|
|||||||
x: x,
|
x: x,
|
||||||
y: y
|
y: y
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Chart.Tooltip = Element.extend({
|
var exports = module.exports = Element.extend({
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this._model = getBaseModel(this._options);
|
this._model = getBaseModel(this._options);
|
||||||
this._lastActive = [];
|
this._lastActive = [];
|
||||||
@ -502,7 +572,7 @@ module.exports = function(Chart) {
|
|||||||
|
|
||||||
var labelColors = [];
|
var labelColors = [];
|
||||||
var labelTextColors = [];
|
var labelTextColors = [];
|
||||||
tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition);
|
tooltipPosition = positioners[opts.position].call(me, active, me._eventPosition);
|
||||||
|
|
||||||
var tooltipItems = [];
|
var tooltipItems = [];
|
||||||
for (i = 0, len = active.length; i < len; ++i) {
|
for (i = 0, len = active.length; i < len; ++i) {
|
||||||
@ -575,6 +645,7 @@ module.exports = function(Chart) {
|
|||||||
|
|
||||||
return me;
|
return me;
|
||||||
},
|
},
|
||||||
|
|
||||||
drawCaret: function(tooltipPoint, size) {
|
drawCaret: function(tooltipPoint, size) {
|
||||||
var ctx = this._chart.ctx;
|
var ctx = this._chart.ctx;
|
||||||
var vm = this._view;
|
var vm = this._view;
|
||||||
@ -643,6 +714,7 @@ module.exports = function(Chart) {
|
|||||||
}
|
}
|
||||||
return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
|
return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
|
||||||
},
|
},
|
||||||
|
|
||||||
drawTitle: function(pt, vm, ctx, opacity) {
|
drawTitle: function(pt, vm, ctx, opacity) {
|
||||||
var title = vm.title;
|
var title = vm.title;
|
||||||
|
|
||||||
@ -667,6 +739,7 @@ module.exports = function(Chart) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
drawBody: function(pt, vm, ctx, opacity) {
|
drawBody: function(pt, vm, ctx, opacity) {
|
||||||
var bodyFontSize = vm.bodyFontSize;
|
var bodyFontSize = vm.bodyFontSize;
|
||||||
var bodySpacing = vm.bodySpacing;
|
var bodySpacing = vm.bodySpacing;
|
||||||
@ -727,6 +800,7 @@ module.exports = function(Chart) {
|
|||||||
helpers.each(vm.afterBody, fillLineOfText);
|
helpers.each(vm.afterBody, fillLineOfText);
|
||||||
pt.y -= bodySpacing; // Remove last body spacing
|
pt.y -= bodySpacing; // Remove last body spacing
|
||||||
},
|
},
|
||||||
|
|
||||||
drawFooter: function(pt, vm, ctx, opacity) {
|
drawFooter: function(pt, vm, ctx, opacity) {
|
||||||
var footer = vm.footer;
|
var footer = vm.footer;
|
||||||
|
|
||||||
@ -745,6 +819,7 @@ module.exports = function(Chart) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
|
drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
|
||||||
ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
|
ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
|
||||||
ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
|
ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
|
||||||
@ -787,6 +862,7 @@ module.exports = function(Chart) {
|
|||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
draw: function() {
|
draw: function() {
|
||||||
var ctx = this._chart.ctx;
|
var ctx = this._chart.ctx;
|
||||||
var vm = this._view;
|
var vm = this._view;
|
||||||
@ -869,80 +945,10 @@ module.exports = function(Chart) {
|
|||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @namespace Chart.Tooltip.positioners
|
* @namespace Chart.Tooltip.positioners
|
||||||
*/
|
*/
|
||||||
Chart.Tooltip.positioners = {
|
exports.positioners = positioners;
|
||||||
/**
|
|
||||||
* Average mode places the tooltip at the average position of the elements shown
|
|
||||||
* @function Chart.Tooltip.positioners.average
|
|
||||||
* @param elements {ChartElement[]} the elements being displayed in the tooltip
|
|
||||||
* @returns {Point} tooltip position
|
|
||||||
*/
|
|
||||||
average: function(elements) {
|
|
||||||
if (!elements.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var i, len;
|
|
||||||
var x = 0;
|
|
||||||
var y = 0;
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
for (i = 0, len = elements.length; i < len; ++i) {
|
|
||||||
var el = elements[i];
|
|
||||||
if (el && el.hasValue()) {
|
|
||||||
var pos = el.tooltipPosition();
|
|
||||||
x += pos.x;
|
|
||||||
y += pos.y;
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
x: Math.round(x / count),
|
|
||||||
y: Math.round(y / count)
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the tooltip position nearest of the item nearest to the event position
|
|
||||||
* @function Chart.Tooltip.positioners.nearest
|
|
||||||
* @param elements {Chart.Element[]} the tooltip elements
|
|
||||||
* @param eventPosition {Point} the position of the event in canvas coordinates
|
|
||||||
* @returns {Point} the tooltip position
|
|
||||||
*/
|
|
||||||
nearest: function(elements, eventPosition) {
|
|
||||||
var x = eventPosition.x;
|
|
||||||
var y = eventPosition.y;
|
|
||||||
var minDistance = Number.POSITIVE_INFINITY;
|
|
||||||
var i, len, nearestElement;
|
|
||||||
|
|
||||||
for (i = 0, len = elements.length; i < len; ++i) {
|
|
||||||
var el = elements[i];
|
|
||||||
if (el && el.hasValue()) {
|
|
||||||
var center = el.getCenterPoint();
|
|
||||||
var d = helpers.distanceBetweenPoints(eventPosition, center);
|
|
||||||
|
|
||||||
if (d < minDistance) {
|
|
||||||
minDistance = d;
|
|
||||||
nearestElement = el;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nearestElement) {
|
|
||||||
var tp = nearestElement.tooltipPosition();
|
|
||||||
x = tp.x;
|
|
||||||
y = tp.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
x: x,
|
|
||||||
y: y
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
// Test the bubble chart default config
|
|
||||||
describe('Default Configs', function() {
|
describe('Default Configs', function() {
|
||||||
describe('Bubble Chart', function() {
|
describe('Bubble Chart', function() {
|
||||||
it('should return correct tooltip strings', function() {
|
it('should return correct tooltip strings', function() {
|
||||||
|
|||||||
44
test/specs/global.namespace.tests.js
Normal file
44
test/specs/global.namespace.tests.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
describe('Chart namespace', function() {
|
||||||
|
describe('Chart', function() {
|
||||||
|
it('should a function (constructor)', function() {
|
||||||
|
expect(Chart instanceof Function).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should define "core" properties', function() {
|
||||||
|
expect(Chart instanceof Function).toBeTruthy();
|
||||||
|
expect(Chart.Animation instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.animationService instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.defaults instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.Element instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.Interaction instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.layouts instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.plugins instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.platform instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.Ticks instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.Tooltip instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.Tooltip.positioners instanceof Object).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Chart.elements', function() {
|
||||||
|
it('should be an object', function() {
|
||||||
|
expect(Chart.elements instanceof Object).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should contains "elements" classes', function() {
|
||||||
|
expect(Chart.elements.Arc instanceof Function).toBeTruthy();
|
||||||
|
expect(Chart.elements.Line instanceof Function).toBeTruthy();
|
||||||
|
expect(Chart.elements.Point instanceof Function).toBeTruthy();
|
||||||
|
expect(Chart.elements.Rectangle instanceof Function).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Chart.helpers', function() {
|
||||||
|
it('should be an object', function() {
|
||||||
|
expect(Chart.helpers instanceof Object).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should contains "helpers" namespaces', function() {
|
||||||
|
expect(Chart.helpers.easing instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.helpers.canvas instanceof Object).toBeTruthy();
|
||||||
|
expect(Chart.helpers.options instanceof Object).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user