Remove const me = this pattern (#9646)

This commit is contained in:
Evert Timberg
2021-09-14 07:37:22 -04:00
committed by GitHub
parent 183a1a9f67
commit 8e68481ec4
28 changed files with 1166 additions and 1382 deletions

View File

@@ -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);
}
}
}

View File

@@ -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,

View File

@@ -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);
}
}