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",
|
||||
"line-end-style": false,
|
||||
"attr-quote-style": "double",
|
||||
"spec-char-escape": false,
|
||||
"attr-bans": [
|
||||
|
||||
@ -8,6 +8,8 @@ Chart.helpers = require('./helpers/index');
|
||||
// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
|
||||
require('./core/core.helpers')(Chart);
|
||||
|
||||
Chart.Animation = require('./core/core.animation');
|
||||
Chart.animationService = require('./core/core.animations');
|
||||
Chart.defaults = require('./core/core.defaults');
|
||||
Chart.Element = require('./core/core.element');
|
||||
Chart.elements = require('./elements/index');
|
||||
@ -16,13 +18,12 @@ Chart.layouts = require('./core/core.layouts');
|
||||
Chart.platform = require('./platforms/platform');
|
||||
Chart.plugins = require('./core/core.plugins');
|
||||
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.datasetController')(Chart);
|
||||
require('./core/core.scaleService')(Chart);
|
||||
require('./core/core.scale')(Chart);
|
||||
require('./core/core.tooltip')(Chart);
|
||||
|
||||
require('./scales/scale.linearbase')(Chart);
|
||||
require('./scales/scale.category')(Chart);
|
||||
|
||||
@ -1,22 +1,8 @@
|
||||
/* global window: false */
|
||||
'use strict';
|
||||
|
||||
var defaults = require('./core.defaults');
|
||||
var Element = require('./core.element');
|
||||
var helpers = require('../helpers/index');
|
||||
|
||||
defaults._set('global', {
|
||||
animation: {
|
||||
duration: 1000,
|
||||
easing: 'easeOutQuart',
|
||||
onProgress: helpers.noop,
|
||||
onComplete: helpers.noop
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
Chart.Animation = Element.extend({
|
||||
var exports = module.exports = Element.extend({
|
||||
chart: null, // the animation associated chart instance
|
||||
currentStep: 0, // the current animation step
|
||||
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
|
||||
onAnimationComplete: null, // user specified callback to fire when the animation finishes
|
||||
});
|
||||
});
|
||||
|
||||
Chart.animationService = {
|
||||
frameDuration: 17,
|
||||
animations: [],
|
||||
dropFrames: 0,
|
||||
request: null,
|
||||
// DEPRECATIONS
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @prop Chart.Animation#animationObject
|
||||
* @deprecated since version 2.6.0
|
||||
* @todo remove at version 3
|
||||
*/
|
||||
Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
|
||||
Object.defineProperty(exports.prototype, 'animationObject', {
|
||||
get: function() {
|
||||
return this;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
/**
|
||||
* Provided for backward compatibility, use Chart.Animation#chart instead
|
||||
* @prop Chart.Animation#chartInstance
|
||||
* @deprecated since version 2.6.0
|
||||
* @todo remove at version 3
|
||||
*/
|
||||
Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
|
||||
Object.defineProperty(exports.prototype, 'chartInstance', {
|
||||
get: function() {
|
||||
return this.chart;
|
||||
},
|
||||
set: function(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';
|
||||
|
||||
var Animation = require('./core.animation');
|
||||
var animations = require('./core.animations');
|
||||
var defaults = require('./core.defaults');
|
||||
var helpers = require('../helpers/index');
|
||||
var Interaction = require('./core.interaction');
|
||||
var layouts = require('./core.layouts');
|
||||
var platform = require('../platforms/platform');
|
||||
var plugins = require('./core.plugins');
|
||||
var Tooltip = require('./core.tooltip');
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
@ -164,7 +167,7 @@ module.exports = function(Chart) {
|
||||
|
||||
stop: function() {
|
||||
// Stops any current animation loop occurring
|
||||
Chart.animationService.cancelAnimation(this);
|
||||
animations.cancelAnimation(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -519,7 +522,7 @@ module.exports = function(Chart) {
|
||||
};
|
||||
|
||||
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
|
||||
easing: config.easing || animationOptions.easing,
|
||||
|
||||
@ -535,12 +538,12 @@ module.exports = function(Chart) {
|
||||
onAnimationComplete: onComplete
|
||||
});
|
||||
|
||||
Chart.animationService.addAnimation(me, animation, duration, lazy);
|
||||
animations.addAnimation(me, animation, duration, lazy);
|
||||
} else {
|
||||
me.draw();
|
||||
|
||||
// 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;
|
||||
@ -775,7 +778,7 @@ module.exports = function(Chart) {
|
||||
|
||||
initToolTip: function() {
|
||||
var me = this;
|
||||
me.tooltip = new Chart.Tooltip({
|
||||
me.tooltip = new Tooltip({
|
||||
_chart: me,
|
||||
_chartInstance: me, // deprecated, backward compatibility
|
||||
_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) {
|
||||
var color = helpers.color(colorString);
|
||||
return color.alpha(opacity * color.alpha()).rgbaString();
|
||||
average: function(elements) {
|
||||
if (!elements.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper to push or concat based on if the 2nd parameter is an array or not
|
||||
function pushOrConcat(base, toPush) {
|
||||
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
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 (helpers.isArray(toPush)) {
|
||||
// base = base.concat(toPush);
|
||||
@ -118,12 +188,12 @@ module.exports = function(Chart) {
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
// Private helper to create a tooltip item model
|
||||
// @param element : the chart element (point, arc, bar) to create the tooltip item for
|
||||
// @return : new tooltip item
|
||||
function createTooltipItem(element) {
|
||||
// Private helper to create a tooltip item model
|
||||
// @param element : the chart element (point, arc, bar) to create the tooltip item for
|
||||
// @return : new tooltip item
|
||||
function createTooltipItem(element) {
|
||||
var xScale = element._xScale;
|
||||
var yScale = element._yScale || element._scale; // handle radar || polarArea charts
|
||||
var index = element._index;
|
||||
@ -137,13 +207,13 @@ module.exports = function(Chart) {
|
||||
x: element._model.x,
|
||||
y: element._model.y
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Helper to get the reset model for the tooltip
|
||||
* @param tooltipOpts {Object} the tooltip options
|
||||
*/
|
||||
function getBaseModel(tooltipOpts) {
|
||||
function getBaseModel(tooltipOpts) {
|
||||
var globalDefaults = defaults.global;
|
||||
var valueOrDefault = helpers.valueOrDefault;
|
||||
|
||||
@ -190,12 +260,12 @@ module.exports = function(Chart) {
|
||||
borderColor: tooltipOpts.borderColor,
|
||||
borderWidth: tooltipOpts.borderWidth
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the size of the tooltip
|
||||
*/
|
||||
function getTooltipSize(tooltip, model) {
|
||||
function getTooltipSize(tooltip, model) {
|
||||
var ctx = tooltip._chart.ctx;
|
||||
|
||||
var height = model.yPadding * 2; // Tooltip Padding
|
||||
@ -258,12 +328,12 @@ module.exports = function(Chart) {
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Helper to get the alignment of a tooltip given the size
|
||||
*/
|
||||
function determineAlignment(tooltip, size) {
|
||||
function determineAlignment(tooltip, size) {
|
||||
var model = tooltip._model;
|
||||
var chart = tooltip._chart;
|
||||
var chartArea = tooltip._chart.chartArea;
|
||||
@ -331,12 +401,12 @@ module.exports = function(Chart) {
|
||||
xAlign: opts.xAlign ? opts.xAlign : xAlign,
|
||||
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
|
||||
*/
|
||||
function getBackgroundPoint(vm, size, alignment, chart) {
|
||||
function getBackgroundPoint(vm, size, alignment, chart) {
|
||||
// Background Position
|
||||
var x = vm.x;
|
||||
var y = vm.y;
|
||||
@ -385,9 +455,9 @@ module.exports = function(Chart) {
|
||||
x: x,
|
||||
y: y
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Chart.Tooltip = Element.extend({
|
||||
var exports = module.exports = Element.extend({
|
||||
initialize: function() {
|
||||
this._model = getBaseModel(this._options);
|
||||
this._lastActive = [];
|
||||
@ -502,7 +572,7 @@ module.exports = function(Chart) {
|
||||
|
||||
var labelColors = [];
|
||||
var labelTextColors = [];
|
||||
tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition);
|
||||
tooltipPosition = positioners[opts.position].call(me, active, me._eventPosition);
|
||||
|
||||
var tooltipItems = [];
|
||||
for (i = 0, len = active.length; i < len; ++i) {
|
||||
@ -575,6 +645,7 @@ module.exports = function(Chart) {
|
||||
|
||||
return me;
|
||||
},
|
||||
|
||||
drawCaret: function(tooltipPoint, size) {
|
||||
var ctx = this._chart.ctx;
|
||||
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};
|
||||
},
|
||||
|
||||
drawTitle: function(pt, vm, ctx, opacity) {
|
||||
var title = vm.title;
|
||||
|
||||
@ -667,6 +739,7 @@ module.exports = function(Chart) {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
drawBody: function(pt, vm, ctx, opacity) {
|
||||
var bodyFontSize = vm.bodyFontSize;
|
||||
var bodySpacing = vm.bodySpacing;
|
||||
@ -727,6 +800,7 @@ module.exports = function(Chart) {
|
||||
helpers.each(vm.afterBody, fillLineOfText);
|
||||
pt.y -= bodySpacing; // Remove last body spacing
|
||||
},
|
||||
|
||||
drawFooter: function(pt, vm, ctx, opacity) {
|
||||
var footer = vm.footer;
|
||||
|
||||
@ -745,6 +819,7 @@ module.exports = function(Chart) {
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
|
||||
ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
|
||||
ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
|
||||
@ -787,6 +862,7 @@ module.exports = function(Chart) {
|
||||
ctx.stroke();
|
||||
}
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
var ctx = this._chart.ctx;
|
||||
var vm = this._view;
|
||||
@ -869,80 +945,10 @@ module.exports = function(Chart) {
|
||||
|
||||
return changed;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
/**
|
||||
* @namespace Chart.Tooltip.positioners
|
||||
*/
|
||||
Chart.Tooltip.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;
|
||||
}
|
||||
exports.positioners = positioners;
|
||||
|
||||
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('Bubble Chart', 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