mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-13 11:46:55 +01:00
Remove const me = this pattern (#9646)
This commit is contained in:
@@ -72,95 +72,88 @@ export class Legend extends Element {
|
||||
}
|
||||
|
||||
update(maxWidth, maxHeight, margins) {
|
||||
const me = this;
|
||||
this.maxWidth = maxWidth;
|
||||
this.maxHeight = maxHeight;
|
||||
this._margins = margins;
|
||||
|
||||
me.maxWidth = maxWidth;
|
||||
me.maxHeight = maxHeight;
|
||||
me._margins = margins;
|
||||
|
||||
me.setDimensions();
|
||||
me.buildLabels();
|
||||
me.fit();
|
||||
this.setDimensions();
|
||||
this.buildLabels();
|
||||
this.fit();
|
||||
}
|
||||
|
||||
setDimensions() {
|
||||
const me = this;
|
||||
|
||||
if (me.isHorizontal()) {
|
||||
me.width = me.maxWidth;
|
||||
me.left = me._margins.left;
|
||||
me.right = me.width;
|
||||
if (this.isHorizontal()) {
|
||||
this.width = this.maxWidth;
|
||||
this.left = this._margins.left;
|
||||
this.right = this.width;
|
||||
} else {
|
||||
me.height = me.maxHeight;
|
||||
me.top = me._margins.top;
|
||||
me.bottom = me.height;
|
||||
this.height = this.maxHeight;
|
||||
this.top = this._margins.top;
|
||||
this.bottom = this.height;
|
||||
}
|
||||
}
|
||||
|
||||
buildLabels() {
|
||||
const me = this;
|
||||
const labelOpts = me.options.labels || {};
|
||||
let legendItems = call(labelOpts.generateLabels, [me.chart], me) || [];
|
||||
const labelOpts = this.options.labels || {};
|
||||
let legendItems = call(labelOpts.generateLabels, [this.chart], this) || [];
|
||||
|
||||
if (labelOpts.filter) {
|
||||
legendItems = legendItems.filter((item) => labelOpts.filter(item, me.chart.data));
|
||||
legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data));
|
||||
}
|
||||
|
||||
if (labelOpts.sort) {
|
||||
legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, me.chart.data));
|
||||
legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, this.chart.data));
|
||||
}
|
||||
|
||||
if (me.options.reverse) {
|
||||
if (this.options.reverse) {
|
||||
legendItems.reverse();
|
||||
}
|
||||
|
||||
me.legendItems = legendItems;
|
||||
this.legendItems = legendItems;
|
||||
}
|
||||
|
||||
fit() {
|
||||
const me = this;
|
||||
const {options, ctx} = me;
|
||||
const {options, ctx} = this;
|
||||
|
||||
// The legend may not be displayed for a variety of reasons including
|
||||
// the fact that the defaults got set to `false`.
|
||||
// When the legend is not displayed, there are no guarantees that the options
|
||||
// are correctly formatted so we need to bail out as early as possible.
|
||||
if (!options.display) {
|
||||
me.width = me.height = 0;
|
||||
this.width = this.height = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const labelOpts = options.labels;
|
||||
const labelFont = toFont(labelOpts.font);
|
||||
const fontSize = labelFont.size;
|
||||
const titleHeight = me._computeTitleHeight();
|
||||
const titleHeight = this._computeTitleHeight();
|
||||
const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize);
|
||||
|
||||
let width, height;
|
||||
|
||||
ctx.font = labelFont.string;
|
||||
|
||||
if (me.isHorizontal()) {
|
||||
width = me.maxWidth; // fill all the width
|
||||
height = me._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
|
||||
if (this.isHorizontal()) {
|
||||
width = this.maxWidth; // fill all the width
|
||||
height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
|
||||
} else {
|
||||
height = me.maxHeight; // fill all the height
|
||||
width = me._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10;
|
||||
height = this.maxHeight; // fill all the height
|
||||
width = this._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10;
|
||||
}
|
||||
|
||||
me.width = Math.min(width, options.maxWidth || me.maxWidth);
|
||||
me.height = Math.min(height, options.maxHeight || me.maxHeight);
|
||||
this.width = Math.min(width, options.maxWidth || this.maxWidth);
|
||||
this.height = Math.min(height, options.maxHeight || this.maxHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
|
||||
const me = this;
|
||||
const {ctx, maxWidth, options: {labels: {padding}}} = me;
|
||||
const hitboxes = me.legendHitBoxes = [];
|
||||
const {ctx, maxWidth, options: {labels: {padding}}} = this;
|
||||
const hitboxes = this.legendHitBoxes = [];
|
||||
// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
|
||||
const lineWidths = me.lineWidths = [0];
|
||||
const lineWidths = this.lineWidths = [0];
|
||||
const lineHeight = itemHeight + padding;
|
||||
let totalHeight = titleHeight;
|
||||
|
||||
@@ -169,7 +162,7 @@ export class Legend extends Element {
|
||||
|
||||
let row = -1;
|
||||
let top = -lineHeight;
|
||||
me.legendItems.forEach((legendItem, i) => {
|
||||
this.legendItems.forEach((legendItem, i) => {
|
||||
const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
|
||||
|
||||
if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
|
||||
@@ -188,10 +181,9 @@ export class Legend extends Element {
|
||||
}
|
||||
|
||||
_fitCols(titleHeight, fontSize, boxWidth, itemHeight) {
|
||||
const me = this;
|
||||
const {ctx, maxHeight, options: {labels: {padding}}} = me;
|
||||
const hitboxes = me.legendHitBoxes = [];
|
||||
const columnSizes = me.columnSizes = [];
|
||||
const {ctx, maxHeight, options: {labels: {padding}}} = this;
|
||||
const hitboxes = this.legendHitBoxes = [];
|
||||
const columnSizes = this.columnSizes = [];
|
||||
const heightLimit = maxHeight - titleHeight;
|
||||
|
||||
let totalWidth = padding;
|
||||
@@ -201,7 +193,7 @@ export class Legend extends Element {
|
||||
let left = 0;
|
||||
let col = 0;
|
||||
|
||||
me.legendItems.forEach((legendItem, i) => {
|
||||
this.legendItems.forEach((legendItem, i) => {
|
||||
const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
|
||||
|
||||
// If too tall, go to new column
|
||||
@@ -228,35 +220,34 @@ export class Legend extends Element {
|
||||
}
|
||||
|
||||
adjustHitBoxes() {
|
||||
const me = this;
|
||||
if (!me.options.display) {
|
||||
if (!this.options.display) {
|
||||
return;
|
||||
}
|
||||
const titleHeight = me._computeTitleHeight();
|
||||
const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = me;
|
||||
const rtlHelper = getRtlAdapter(rtl, me.left, me.width);
|
||||
const titleHeight = this._computeTitleHeight();
|
||||
const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = this;
|
||||
const rtlHelper = getRtlAdapter(rtl, this.left, this.width);
|
||||
if (this.isHorizontal()) {
|
||||
let row = 0;
|
||||
let left = _alignStartEnd(align, me.left + padding, me.right - me.lineWidths[row]);
|
||||
let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);
|
||||
for (const hitbox of hitboxes) {
|
||||
if (row !== hitbox.row) {
|
||||
row = hitbox.row;
|
||||
left = _alignStartEnd(align, me.left + padding, me.right - me.lineWidths[row]);
|
||||
left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);
|
||||
}
|
||||
hitbox.top += me.top + titleHeight + padding;
|
||||
hitbox.top += this.top + titleHeight + padding;
|
||||
hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);
|
||||
left += hitbox.width + padding;
|
||||
}
|
||||
} else {
|
||||
let col = 0;
|
||||
let top = _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - me.columnSizes[col].height);
|
||||
let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
|
||||
for (const hitbox of hitboxes) {
|
||||
if (hitbox.col !== col) {
|
||||
col = hitbox.col;
|
||||
top = _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - me.columnSizes[col].height);
|
||||
top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
|
||||
}
|
||||
hitbox.top = top;
|
||||
hitbox.left += me.left + padding;
|
||||
hitbox.left += this.left + padding;
|
||||
hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);
|
||||
top += hitbox.height + padding;
|
||||
}
|
||||
@@ -268,12 +259,11 @@ export class Legend extends Element {
|
||||
}
|
||||
|
||||
draw() {
|
||||
const me = this;
|
||||
if (me.options.display) {
|
||||
const ctx = me.ctx;
|
||||
clipArea(ctx, me);
|
||||
if (this.options.display) {
|
||||
const ctx = this.ctx;
|
||||
clipArea(ctx, this);
|
||||
|
||||
me._draw();
|
||||
this._draw();
|
||||
|
||||
unclipArea(ctx);
|
||||
}
|
||||
@@ -283,18 +273,17 @@ export class Legend extends Element {
|
||||
* @private
|
||||
*/
|
||||
_draw() {
|
||||
const me = this;
|
||||
const {options: opts, columnSizes, lineWidths, ctx} = me;
|
||||
const {options: opts, columnSizes, lineWidths, ctx} = this;
|
||||
const {align, labels: labelOpts} = opts;
|
||||
const defaultColor = defaults.color;
|
||||
const rtlHelper = getRtlAdapter(opts.rtl, me.left, me.width);
|
||||
const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);
|
||||
const labelFont = toFont(labelOpts.font);
|
||||
const {color: fontColor, padding} = labelOpts;
|
||||
const fontSize = labelFont.size;
|
||||
const halfFontSize = fontSize / 2;
|
||||
let cursor;
|
||||
|
||||
me.drawTitle();
|
||||
this.drawTitle();
|
||||
|
||||
// Canvas setup
|
||||
ctx.textAlign = rtlHelper.textAlign('left');
|
||||
@@ -375,26 +364,26 @@ export class Legend extends Element {
|
||||
};
|
||||
|
||||
// Horizontal
|
||||
const isHorizontal = me.isHorizontal();
|
||||
const isHorizontal = this.isHorizontal();
|
||||
const titleHeight = this._computeTitleHeight();
|
||||
if (isHorizontal) {
|
||||
cursor = {
|
||||
x: _alignStartEnd(align, me.left + padding, me.right - lineWidths[0]),
|
||||
y: me.top + padding + titleHeight,
|
||||
x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]),
|
||||
y: this.top + padding + titleHeight,
|
||||
line: 0
|
||||
};
|
||||
} else {
|
||||
cursor = {
|
||||
x: me.left + padding,
|
||||
y: _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - columnSizes[0].height),
|
||||
x: this.left + padding,
|
||||
y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),
|
||||
line: 0
|
||||
};
|
||||
}
|
||||
|
||||
overrideTextDirection(me.ctx, opts.textDirection);
|
||||
overrideTextDirection(this.ctx, opts.textDirection);
|
||||
|
||||
const lineHeight = itemHeight + padding;
|
||||
me.legendItems.forEach((legendItem, i) => {
|
||||
this.legendItems.forEach((legendItem, i) => {
|
||||
// TODO: Remove fallbacks at v4
|
||||
ctx.strokeStyle = legendItem.fontColor || fontColor; // for strikethrough effect
|
||||
ctx.fillStyle = legendItem.fontColor || fontColor; // render in correct colour
|
||||
@@ -405,25 +394,25 @@ export class Legend extends Element {
|
||||
let x = cursor.x;
|
||||
let y = cursor.y;
|
||||
|
||||
rtlHelper.setWidth(me.width);
|
||||
rtlHelper.setWidth(this.width);
|
||||
|
||||
if (isHorizontal) {
|
||||
if (i > 0 && x + width + padding > me.right) {
|
||||
if (i > 0 && x + width + padding > this.right) {
|
||||
y = cursor.y += lineHeight;
|
||||
cursor.line++;
|
||||
x = cursor.x = _alignStartEnd(align, me.left + padding, me.right - lineWidths[cursor.line]);
|
||||
x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]);
|
||||
}
|
||||
} else if (i > 0 && y + lineHeight > me.bottom) {
|
||||
} else if (i > 0 && y + lineHeight > this.bottom) {
|
||||
x = cursor.x = x + columnSizes[cursor.line].width + padding;
|
||||
cursor.line++;
|
||||
y = cursor.y = _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - columnSizes[cursor.line].height);
|
||||
y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);
|
||||
}
|
||||
|
||||
const realX = rtlHelper.x(x);
|
||||
|
||||
drawLegendBox(realX, y, legendItem);
|
||||
|
||||
x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : me.right, opts.rtl);
|
||||
x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl);
|
||||
|
||||
// Fill the actual label
|
||||
fillText(rtlHelper.x(x), y, legendItem);
|
||||
@@ -435,15 +424,14 @@ export class Legend extends Element {
|
||||
}
|
||||
});
|
||||
|
||||
restoreTextDirection(me.ctx, opts.textDirection);
|
||||
restoreTextDirection(this.ctx, opts.textDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
drawTitle() {
|
||||
const me = this;
|
||||
const opts = me.options;
|
||||
const opts = this.options;
|
||||
const titleOpts = opts.title;
|
||||
const titleFont = toFont(titleOpts.font);
|
||||
const titlePadding = toPadding(titleOpts.padding);
|
||||
@@ -452,8 +440,8 @@ export class Legend extends Element {
|
||||
return;
|
||||
}
|
||||
|
||||
const rtlHelper = getRtlAdapter(opts.rtl, me.left, me.width);
|
||||
const ctx = me.ctx;
|
||||
const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);
|
||||
const ctx = this.ctx;
|
||||
const position = titleOpts.position;
|
||||
const halfFontSize = titleFont.size / 2;
|
||||
const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
|
||||
@@ -461,18 +449,18 @@ export class Legend extends Element {
|
||||
|
||||
// These defaults are used when the legend is vertical.
|
||||
// When horizontal, they are computed below.
|
||||
let left = me.left;
|
||||
let maxWidth = me.width;
|
||||
let left = this.left;
|
||||
let maxWidth = this.width;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
// Move left / right so that the title is above the legend lines
|
||||
maxWidth = Math.max(...me.lineWidths);
|
||||
y = me.top + topPaddingPlusHalfFontSize;
|
||||
left = _alignStartEnd(opts.align, left, me.right - maxWidth);
|
||||
maxWidth = Math.max(...this.lineWidths);
|
||||
y = this.top + topPaddingPlusHalfFontSize;
|
||||
left = _alignStartEnd(opts.align, left, this.right - maxWidth);
|
||||
} else {
|
||||
// Move down so that the title is above the legend stack in every alignment
|
||||
const maxHeight = me.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0);
|
||||
y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, me.top, me.bottom - maxHeight - opts.labels.padding - me._computeTitleHeight());
|
||||
const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0);
|
||||
y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());
|
||||
}
|
||||
|
||||
// Now that we know the left edge of the inner legend box, compute the correct
|
||||
@@ -503,18 +491,17 @@ export class Legend extends Element {
|
||||
* @private
|
||||
*/
|
||||
_getLegendItemAt(x, y) {
|
||||
const me = this;
|
||||
let i, hitBox, lh;
|
||||
|
||||
if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
|
||||
if (x >= this.left && x <= this.right && y >= this.top && y <= this.bottom) {
|
||||
// See if we are touching one of the dataset boxes
|
||||
lh = me.legendHitBoxes;
|
||||
lh = this.legendHitBoxes;
|
||||
for (i = 0; i < lh.length; ++i) {
|
||||
hitBox = lh[i];
|
||||
|
||||
if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
|
||||
// Touching an element
|
||||
return me.legendItems[i];
|
||||
return this.legendItems[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -527,29 +514,28 @@ export class Legend extends Element {
|
||||
* @param {ChartEvent} e - The event to handle
|
||||
*/
|
||||
handleEvent(e) {
|
||||
const me = this;
|
||||
const opts = me.options;
|
||||
const opts = this.options;
|
||||
if (!isListened(e.type, opts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Chart event already has relative position in it
|
||||
const hoveredItem = me._getLegendItemAt(e.x, e.y);
|
||||
const hoveredItem = this._getLegendItemAt(e.x, e.y);
|
||||
|
||||
if (e.type === 'mousemove') {
|
||||
const previous = me._hoveredItem;
|
||||
const previous = this._hoveredItem;
|
||||
const sameItem = itemsEqual(previous, hoveredItem);
|
||||
if (previous && !sameItem) {
|
||||
call(opts.onLeave, [e, previous, me], me);
|
||||
call(opts.onLeave, [e, previous, this], this);
|
||||
}
|
||||
|
||||
me._hoveredItem = hoveredItem;
|
||||
this._hoveredItem = hoveredItem;
|
||||
|
||||
if (hoveredItem && !sameItem) {
|
||||
call(opts.onHover, [e, hoveredItem, me], me);
|
||||
call(opts.onHover, [e, hoveredItem, this], this);
|
||||
}
|
||||
} else if (hoveredItem) {
|
||||
call(opts.onClick, [e, hoveredItem, me], me);
|
||||
call(opts.onClick, [e, hoveredItem, this], this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,28 +27,27 @@ export class Title extends Element {
|
||||
}
|
||||
|
||||
update(maxWidth, maxHeight) {
|
||||
const me = this;
|
||||
const opts = me.options;
|
||||
const opts = this.options;
|
||||
|
||||
me.left = 0;
|
||||
me.top = 0;
|
||||
this.left = 0;
|
||||
this.top = 0;
|
||||
|
||||
if (!opts.display) {
|
||||
me.width = me.height = me.right = me.bottom = 0;
|
||||
this.width = this.height = this.right = this.bottom = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
me.width = me.right = maxWidth;
|
||||
me.height = me.bottom = maxHeight;
|
||||
this.width = this.right = maxWidth;
|
||||
this.height = this.bottom = maxHeight;
|
||||
|
||||
const lineCount = isArray(opts.text) ? opts.text.length : 1;
|
||||
me._padding = toPadding(opts.padding);
|
||||
const textSize = lineCount * toFont(opts.font).lineHeight + me._padding.height;
|
||||
this._padding = toPadding(opts.padding);
|
||||
const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height;
|
||||
|
||||
if (me.isHorizontal()) {
|
||||
me.height = textSize;
|
||||
if (this.isHorizontal()) {
|
||||
this.height = textSize;
|
||||
} else {
|
||||
me.width = textSize;
|
||||
this.width = textSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,9 +82,8 @@ export class Title extends Element {
|
||||
}
|
||||
|
||||
draw() {
|
||||
const me = this;
|
||||
const ctx = me.ctx;
|
||||
const opts = me.options;
|
||||
const ctx = this.ctx;
|
||||
const opts = this.options;
|
||||
|
||||
if (!opts.display) {
|
||||
return;
|
||||
@@ -93,8 +91,8 @@ export class Title extends Element {
|
||||
|
||||
const fontOpts = toFont(opts.font);
|
||||
const lineHeight = fontOpts.lineHeight;
|
||||
const offset = lineHeight / 2 + me._padding.top;
|
||||
const {titleX, titleY, maxWidth, rotation} = me._drawArgs(offset);
|
||||
const offset = lineHeight / 2 + this._padding.top;
|
||||
const {titleX, titleY, maxWidth, rotation} = this._drawArgs(offset);
|
||||
|
||||
renderText(ctx, opts.text, 0, 0, fontOpts, {
|
||||
color: opts.color,
|
||||
|
||||
@@ -392,19 +392,18 @@ export class Tooltip extends Element {
|
||||
* @private
|
||||
*/
|
||||
_resolveAnimations() {
|
||||
const me = this;
|
||||
const cached = me._cachedAnimations;
|
||||
const cached = this._cachedAnimations;
|
||||
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const chart = me._chart;
|
||||
const options = me.options.setContext(me.getContext());
|
||||
const chart = this._chart;
|
||||
const options = this.options.setContext(this.getContext());
|
||||
const opts = options.enabled && chart.options.animation && options.animations;
|
||||
const animations = new Animations(me._chart, opts);
|
||||
const animations = new Animations(this._chart, opts);
|
||||
if (opts._cacheable) {
|
||||
me._cachedAnimations = Object.freeze(animations);
|
||||
this._cachedAnimations = Object.freeze(animations);
|
||||
}
|
||||
|
||||
return animations;
|
||||
@@ -414,18 +413,16 @@ export class Tooltip extends Element {
|
||||
* @protected
|
||||
*/
|
||||
getContext() {
|
||||
const me = this;
|
||||
return me.$context ||
|
||||
(me.$context = createTooltipContext(me._chart.getContext(), me, me._tooltipItems));
|
||||
return this.$context ||
|
||||
(this.$context = createTooltipContext(this._chart.getContext(), this, this._tooltipItems));
|
||||
}
|
||||
|
||||
getTitle(context, options) {
|
||||
const me = this;
|
||||
const {callbacks} = options;
|
||||
|
||||
const beforeTitle = callbacks.beforeTitle.apply(me, [context]);
|
||||
const title = callbacks.title.apply(me, [context]);
|
||||
const afterTitle = callbacks.afterTitle.apply(me, [context]);
|
||||
const beforeTitle = callbacks.beforeTitle.apply(this, [context]);
|
||||
const title = callbacks.title.apply(this, [context]);
|
||||
const afterTitle = callbacks.afterTitle.apply(this, [context]);
|
||||
|
||||
let lines = [];
|
||||
lines = pushOrConcat(lines, splitNewlines(beforeTitle));
|
||||
@@ -440,7 +437,6 @@ export class Tooltip extends Element {
|
||||
}
|
||||
|
||||
getBody(tooltipItems, options) {
|
||||
const me = this;
|
||||
const {callbacks} = options;
|
||||
const bodyItems = [];
|
||||
|
||||
@@ -451,9 +447,9 @@ export class Tooltip extends Element {
|
||||
after: []
|
||||
};
|
||||
const scoped = overrideCallbacks(callbacks, context);
|
||||
pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(me, context)));
|
||||
pushOrConcat(bodyItem.lines, scoped.label.call(me, context));
|
||||
pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(me, context)));
|
||||
pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context)));
|
||||
pushOrConcat(bodyItem.lines, scoped.label.call(this, context));
|
||||
pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context)));
|
||||
|
||||
bodyItems.push(bodyItem);
|
||||
});
|
||||
@@ -467,12 +463,11 @@ export class Tooltip extends Element {
|
||||
|
||||
// Get the footer and beforeFooter and afterFooter lines
|
||||
getFooter(tooltipItems, options) {
|
||||
const me = this;
|
||||
const {callbacks} = options;
|
||||
|
||||
const beforeFooter = callbacks.beforeFooter.apply(me, [tooltipItems]);
|
||||
const footer = callbacks.footer.apply(me, [tooltipItems]);
|
||||
const afterFooter = callbacks.afterFooter.apply(me, [tooltipItems]);
|
||||
const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]);
|
||||
const footer = callbacks.footer.apply(this, [tooltipItems]);
|
||||
const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]);
|
||||
|
||||
let lines = [];
|
||||
lines = pushOrConcat(lines, splitNewlines(beforeFooter));
|
||||
@@ -486,9 +481,8 @@ export class Tooltip extends Element {
|
||||
* @private
|
||||
*/
|
||||
_createItems(options) {
|
||||
const me = this;
|
||||
const active = me._active;
|
||||
const data = me._chart.data;
|
||||
const active = this._active;
|
||||
const data = this._chart.data;
|
||||
const labelColors = [];
|
||||
const labelPointStyles = [];
|
||||
const labelTextColors = [];
|
||||
@@ -496,7 +490,7 @@ export class Tooltip extends Element {
|
||||
let i, len;
|
||||
|
||||
for (i = 0, len = active.length; i < len; ++i) {
|
||||
tooltipItems.push(createTooltipItem(me._chart, active[i]));
|
||||
tooltipItems.push(createTooltipItem(this._chart, active[i]));
|
||||
}
|
||||
|
||||
// If the user provided a filter function, use it to modify the tooltip items
|
||||
@@ -512,48 +506,47 @@ export class Tooltip extends Element {
|
||||
// Determine colors for boxes
|
||||
each(tooltipItems, (context) => {
|
||||
const scoped = overrideCallbacks(options.callbacks, context);
|
||||
labelColors.push(scoped.labelColor.call(me, context));
|
||||
labelPointStyles.push(scoped.labelPointStyle.call(me, context));
|
||||
labelTextColors.push(scoped.labelTextColor.call(me, context));
|
||||
labelColors.push(scoped.labelColor.call(this, context));
|
||||
labelPointStyles.push(scoped.labelPointStyle.call(this, context));
|
||||
labelTextColors.push(scoped.labelTextColor.call(this, context));
|
||||
});
|
||||
|
||||
me.labelColors = labelColors;
|
||||
me.labelPointStyles = labelPointStyles;
|
||||
me.labelTextColors = labelTextColors;
|
||||
me.dataPoints = tooltipItems;
|
||||
this.labelColors = labelColors;
|
||||
this.labelPointStyles = labelPointStyles;
|
||||
this.labelTextColors = labelTextColors;
|
||||
this.dataPoints = tooltipItems;
|
||||
return tooltipItems;
|
||||
}
|
||||
|
||||
update(changed, replay) {
|
||||
const me = this;
|
||||
const options = me.options.setContext(me.getContext());
|
||||
const active = me._active;
|
||||
const options = this.options.setContext(this.getContext());
|
||||
const active = this._active;
|
||||
let properties;
|
||||
let tooltipItems = [];
|
||||
|
||||
if (!active.length) {
|
||||
if (me.opacity !== 0) {
|
||||
if (this.opacity !== 0) {
|
||||
properties = {
|
||||
opacity: 0
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const position = positioners[options.position].call(me, active, me._eventPosition);
|
||||
tooltipItems = me._createItems(options);
|
||||
const position = positioners[options.position].call(this, active, this._eventPosition);
|
||||
tooltipItems = this._createItems(options);
|
||||
|
||||
me.title = me.getTitle(tooltipItems, options);
|
||||
me.beforeBody = me.getBeforeBody(tooltipItems, options);
|
||||
me.body = me.getBody(tooltipItems, options);
|
||||
me.afterBody = me.getAfterBody(tooltipItems, options);
|
||||
me.footer = me.getFooter(tooltipItems, options);
|
||||
this.title = this.getTitle(tooltipItems, options);
|
||||
this.beforeBody = this.getBeforeBody(tooltipItems, options);
|
||||
this.body = this.getBody(tooltipItems, options);
|
||||
this.afterBody = this.getAfterBody(tooltipItems, options);
|
||||
this.footer = this.getFooter(tooltipItems, options);
|
||||
|
||||
const size = me._size = getTooltipSize(me, options);
|
||||
const size = this._size = getTooltipSize(this, options);
|
||||
const positionAndSize = Object.assign({}, position, size);
|
||||
const alignment = determineAlignment(me._chart, options, positionAndSize);
|
||||
const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, me._chart);
|
||||
const alignment = determineAlignment(this._chart, options, positionAndSize);
|
||||
const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this._chart);
|
||||
|
||||
me.xAlign = alignment.xAlign;
|
||||
me.yAlign = alignment.yAlign;
|
||||
this.xAlign = alignment.xAlign;
|
||||
this.yAlign = alignment.yAlign;
|
||||
|
||||
properties = {
|
||||
opacity: 1,
|
||||
@@ -566,15 +559,15 @@ export class Tooltip extends Element {
|
||||
};
|
||||
}
|
||||
|
||||
me._tooltipItems = tooltipItems;
|
||||
me.$context = undefined;
|
||||
this._tooltipItems = tooltipItems;
|
||||
this.$context = undefined;
|
||||
|
||||
if (properties) {
|
||||
me._resolveAnimations().update(me, properties);
|
||||
this._resolveAnimations().update(this, properties);
|
||||
}
|
||||
|
||||
if (changed && options.external) {
|
||||
options.external.call(me, {chart: me._chart, tooltip: me, replay});
|
||||
options.external.call(this, {chart: this._chart, tooltip: this, replay});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,15 +637,14 @@ export class Tooltip extends Element {
|
||||
}
|
||||
|
||||
drawTitle(pt, ctx, options) {
|
||||
const me = this;
|
||||
const title = me.title;
|
||||
const title = this.title;
|
||||
const length = title.length;
|
||||
let titleFont, titleSpacing, i;
|
||||
|
||||
if (length) {
|
||||
const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
|
||||
const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
|
||||
|
||||
pt.x = getAlignedX(me, options.titleAlign, options);
|
||||
pt.x = getAlignedX(this, options.titleAlign, options);
|
||||
|
||||
ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
|
||||
ctx.textBaseline = 'middle';
|
||||
@@ -678,12 +670,11 @@ export class Tooltip extends Element {
|
||||
* @private
|
||||
*/
|
||||
_drawColorBox(ctx, pt, i, rtlHelper, options) {
|
||||
const me = this;
|
||||
const labelColors = me.labelColors[i];
|
||||
const labelPointStyle = me.labelPointStyles[i];
|
||||
const labelColors = this.labelColors[i];
|
||||
const labelPointStyle = this.labelPointStyles[i];
|
||||
const {boxHeight, boxWidth, boxPadding} = options;
|
||||
const bodyFont = toFont(options.bodyFont);
|
||||
const colorX = getAlignedX(me, 'left', options);
|
||||
const colorX = getAlignedX(this, 'left', options);
|
||||
const rtlColorX = rtlHelper.x(colorX);
|
||||
const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;
|
||||
const colorY = pt.y + yOffSet;
|
||||
@@ -757,18 +748,17 @@ export class Tooltip extends Element {
|
||||
}
|
||||
|
||||
// restore fillStyle
|
||||
ctx.fillStyle = me.labelTextColors[i];
|
||||
ctx.fillStyle = this.labelTextColors[i];
|
||||
}
|
||||
|
||||
drawBody(pt, ctx, options) {
|
||||
const me = this;
|
||||
const {body} = me;
|
||||
const {body} = this;
|
||||
const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding} = options;
|
||||
const bodyFont = toFont(options.bodyFont);
|
||||
let bodyLineHeight = bodyFont.lineHeight;
|
||||
let xLinePadding = 0;
|
||||
|
||||
const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
|
||||
const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
|
||||
|
||||
const fillLineOfText = function(line) {
|
||||
ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);
|
||||
@@ -782,11 +772,11 @@ export class Tooltip extends Element {
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.font = bodyFont.string;
|
||||
|
||||
pt.x = getAlignedX(me, bodyAlignForCalculation, options);
|
||||
pt.x = getAlignedX(this, bodyAlignForCalculation, options);
|
||||
|
||||
// Before body lines
|
||||
ctx.fillStyle = options.bodyColor;
|
||||
each(me.beforeBody, fillLineOfText);
|
||||
each(this.beforeBody, fillLineOfText);
|
||||
|
||||
xLinePadding = displayColors && bodyAlignForCalculation !== 'right'
|
||||
? bodyAlign === 'center' ? (boxWidth / 2 + boxPadding) : (boxWidth + 2 + boxPadding)
|
||||
@@ -795,7 +785,7 @@ export class Tooltip extends Element {
|
||||
// Draw body lines now
|
||||
for (i = 0, ilen = body.length; i < ilen; ++i) {
|
||||
bodyItem = body[i];
|
||||
textColor = me.labelTextColors[i];
|
||||
textColor = this.labelTextColors[i];
|
||||
|
||||
ctx.fillStyle = textColor;
|
||||
each(bodyItem.before, fillLineOfText);
|
||||
@@ -803,7 +793,7 @@ export class Tooltip extends Element {
|
||||
lines = bodyItem.lines;
|
||||
// Draw Legend-like boxes if needed
|
||||
if (displayColors && lines.length) {
|
||||
me._drawColorBox(ctx, pt, i, rtlHelper, options);
|
||||
this._drawColorBox(ctx, pt, i, rtlHelper, options);
|
||||
bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);
|
||||
}
|
||||
|
||||
@@ -821,20 +811,19 @@ export class Tooltip extends Element {
|
||||
bodyLineHeight = bodyFont.lineHeight;
|
||||
|
||||
// After body lines
|
||||
each(me.afterBody, fillLineOfText);
|
||||
each(this.afterBody, fillLineOfText);
|
||||
pt.y -= bodySpacing; // Remove last body spacing
|
||||
}
|
||||
|
||||
drawFooter(pt, ctx, options) {
|
||||
const me = this;
|
||||
const footer = me.footer;
|
||||
const footer = this.footer;
|
||||
const length = footer.length;
|
||||
let footerFont, i;
|
||||
|
||||
if (length) {
|
||||
const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width);
|
||||
const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
|
||||
|
||||
pt.x = getAlignedX(me, options.footerAlign, options);
|
||||
pt.x = getAlignedX(this, options.footerAlign, options);
|
||||
pt.y += options.footerMarginTop;
|
||||
|
||||
ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
|
||||
@@ -898,50 +887,48 @@ export class Tooltip extends Element {
|
||||
* @private
|
||||
*/
|
||||
_updateAnimationTarget(options) {
|
||||
const me = this;
|
||||
const chart = me._chart;
|
||||
const anims = me.$animations;
|
||||
const chart = this._chart;
|
||||
const anims = this.$animations;
|
||||
const animX = anims && anims.x;
|
||||
const animY = anims && anims.y;
|
||||
if (animX || animY) {
|
||||
const position = positioners[options.position].call(me, me._active, me._eventPosition);
|
||||
const position = positioners[options.position].call(this, this._active, this._eventPosition);
|
||||
if (!position) {
|
||||
return;
|
||||
}
|
||||
const size = me._size = getTooltipSize(me, options);
|
||||
const positionAndSize = Object.assign({}, position, me._size);
|
||||
const size = this._size = getTooltipSize(this, options);
|
||||
const positionAndSize = Object.assign({}, position, this._size);
|
||||
const alignment = determineAlignment(chart, options, positionAndSize);
|
||||
const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
|
||||
if (animX._to !== point.x || animY._to !== point.y) {
|
||||
me.xAlign = alignment.xAlign;
|
||||
me.yAlign = alignment.yAlign;
|
||||
me.width = size.width;
|
||||
me.height = size.height;
|
||||
me.caretX = position.x;
|
||||
me.caretY = position.y;
|
||||
me._resolveAnimations().update(me, point);
|
||||
this.xAlign = alignment.xAlign;
|
||||
this.yAlign = alignment.yAlign;
|
||||
this.width = size.width;
|
||||
this.height = size.height;
|
||||
this.caretX = position.x;
|
||||
this.caretY = position.y;
|
||||
this._resolveAnimations().update(this, point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
const me = this;
|
||||
const options = me.options.setContext(me.getContext());
|
||||
let opacity = me.opacity;
|
||||
const options = this.options.setContext(this.getContext());
|
||||
let opacity = this.opacity;
|
||||
|
||||
if (!opacity) {
|
||||
return;
|
||||
}
|
||||
|
||||
me._updateAnimationTarget(options);
|
||||
this._updateAnimationTarget(options);
|
||||
|
||||
const tooltipSize = {
|
||||
width: me.width,
|
||||
height: me.height
|
||||
width: this.width,
|
||||
height: this.height
|
||||
};
|
||||
const pt = {
|
||||
x: me.x,
|
||||
y: me.y
|
||||
x: this.x,
|
||||
y: this.y
|
||||
};
|
||||
|
||||
// IE11/Edge does not like very small opacities, so snap to 0
|
||||
@@ -950,27 +937,27 @@ export class Tooltip extends Element {
|
||||
const padding = toPadding(options.padding);
|
||||
|
||||
// Truthy/falsey value for empty tooltip
|
||||
const hasTooltipContent = me.title.length || me.beforeBody.length || me.body.length || me.afterBody.length || me.footer.length;
|
||||
const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;
|
||||
|
||||
if (options.enabled && hasTooltipContent) {
|
||||
ctx.save();
|
||||
ctx.globalAlpha = opacity;
|
||||
|
||||
// Draw Background
|
||||
me.drawBackground(pt, ctx, tooltipSize, options);
|
||||
this.drawBackground(pt, ctx, tooltipSize, options);
|
||||
|
||||
overrideTextDirection(ctx, options.textDirection);
|
||||
|
||||
pt.y += padding.top;
|
||||
|
||||
// Titles
|
||||
me.drawTitle(pt, ctx, options);
|
||||
this.drawTitle(pt, ctx, options);
|
||||
|
||||
// Body
|
||||
me.drawBody(pt, ctx, options);
|
||||
this.drawBody(pt, ctx, options);
|
||||
|
||||
// Footer
|
||||
me.drawFooter(pt, ctx, options);
|
||||
this.drawFooter(pt, ctx, options);
|
||||
|
||||
restoreTextDirection(ctx, options.textDirection);
|
||||
|
||||
@@ -992,10 +979,9 @@ export class Tooltip extends Element {
|
||||
* @param {object} eventPosition Synthetic event position used in positioning
|
||||
*/
|
||||
setActiveElements(activeElements, eventPosition) {
|
||||
const me = this;
|
||||
const lastActive = me._active;
|
||||
const lastActive = this._active;
|
||||
const active = activeElements.map(({datasetIndex, index}) => {
|
||||
const meta = me._chart.getDatasetMeta(datasetIndex);
|
||||
const meta = this._chart.getDatasetMeta(datasetIndex);
|
||||
|
||||
if (!meta) {
|
||||
throw new Error('Cannot find a dataset at index ' + datasetIndex);
|
||||
@@ -1008,12 +994,12 @@ export class Tooltip extends Element {
|
||||
};
|
||||
});
|
||||
const changed = !_elementsEqual(lastActive, active);
|
||||
const positionChanged = me._positionChanged(active, eventPosition);
|
||||
const positionChanged = this._positionChanged(active, eventPosition);
|
||||
|
||||
if (changed || positionChanged) {
|
||||
me._active = active;
|
||||
me._eventPosition = eventPosition;
|
||||
me.update(true);
|
||||
this._active = active;
|
||||
this._eventPosition = eventPosition;
|
||||
this.update(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1024,15 +1010,14 @@ export class Tooltip extends Element {
|
||||
* @returns {boolean} true if the tooltip changed
|
||||
*/
|
||||
handleEvent(e, replay) {
|
||||
const me = this;
|
||||
const options = me.options;
|
||||
const lastActive = me._active || [];
|
||||
const options = this.options;
|
||||
const lastActive = this._active || [];
|
||||
let changed = false;
|
||||
let active = [];
|
||||
|
||||
// Find Active Elements for tooltips
|
||||
if (e.type !== 'mouseout') {
|
||||
active = me._chart.getElementsAtEventForMode(e, options.mode, options, replay);
|
||||
active = this._chart.getElementsAtEventForMode(e, options.mode, options, replay);
|
||||
if (options.reverse) {
|
||||
active.reverse();
|
||||
}
|
||||
@@ -1041,22 +1026,22 @@ export class Tooltip extends Element {
|
||||
// When there are multiple items shown, but the tooltip position is nearest mode
|
||||
// an update may need to be made because our position may have changed even though
|
||||
// the items are the same as before.
|
||||
const positionChanged = me._positionChanged(active, e);
|
||||
const positionChanged = this._positionChanged(active, e);
|
||||
|
||||
// Remember Last Actives
|
||||
changed = replay || !_elementsEqual(active, lastActive) || positionChanged;
|
||||
|
||||
// Only handle target event on tooltip change
|
||||
if (changed) {
|
||||
me._active = active;
|
||||
this._active = active;
|
||||
|
||||
if (options.enabled || options.external) {
|
||||
me._eventPosition = {
|
||||
this._eventPosition = {
|
||||
x: e.x,
|
||||
y: e.y
|
||||
};
|
||||
|
||||
me.update(true, replay);
|
||||
this.update(true, replay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user