import {each, noop, isNullOrUndef, isArray, _elementsEqual} from '../helpers/helpers.core';
import {toFont, toPadding} from '../helpers/helpers.options';
import {getRtlAdapter, overrideTextDirection, restoreTextDirection} from '../helpers/helpers.rtl';
-import {distanceBetweenPoints} from '../helpers/helpers.math';
+import {distanceBetweenPoints, _limitValue} from '../helpers/helpers.math';
import {drawPoint} from '../helpers';
/**
return {width, height};
}
-/**
- * Helper to get the alignment of a tooltip given the size
- */
-function determineAlignment(chart, options, size) {
- const {x, y, width, height} = size;
- const chartArea = chart.chartArea;
- let xAlign = 'center';
- let yAlign = 'center';
+function determineYAlign(chart, size) {
+ const {y, height} = size;
if (y < height / 2) {
- yAlign = 'top';
+ return 'top';
} else if (y > (chart.height - height / 2)) {
- yAlign = 'bottom';
+ return 'bottom';
}
+ return 'center';
+}
- let lf, rf; // functions to determine left, right alignment
- const midX = (chartArea.left + chartArea.right) / 2;
- const midY = (chartArea.top + chartArea.bottom) / 2;
+function doesNotFitWithAlign(xAlign, chart, options, size) {
+ const {x, width} = size;
+ const caret = options.caretSize + options.caretPadding;
+ if (xAlign === 'left' && x + width + caret > chart.width) {
+ return true;
+ }
- if (yAlign === 'center') {
- lf = (value) => value <= midX;
- rf = (value) => value > midX;
- } else {
- lf = (value) => value <= (width / 2);
- rf = (value) => value >= (chart.width - (width / 2));
+ if (xAlign === 'right' && x - width - caret < 0) {
+ return true;
}
+}
- // functions to determine if left/right alignment causes tooltip to go outside chart
- const olf = (value) => value + width + options.caretSize + options.caretPadding > chart.width;
- const orf = (value) => value - width - options.caretSize - options.caretPadding < 0;
- // function to get the y alignment if the tooltip goes outside of the left or right edges
- const yf = (value) => value <= midY ? 'top' : 'bottom';
+function determineXAlign(chart, options, size, yAlign) {
+ const {x, width} = size;
+ const {width: chartWidth, chartArea: {left, right}} = chart;
+ let xAlign = 'center';
- if (lf(x)) {
+ if (yAlign === 'center') {
+ xAlign = x <= (left + right) / 2 ? 'left' : 'right';
+ } else if (x <= width / 2) {
xAlign = 'left';
-
- // Is tooltip too wide and goes over the right side of the chart.?
- if (olf(x)) {
- xAlign = 'center';
- yAlign = yf(y);
- }
- } else if (rf(x)) {
+ } else if (x >= chartWidth - width / 2) {
xAlign = 'right';
+ }
- // Is tooltip too wide and goes outside left edge of canvas?
- if (orf(x)) {
- xAlign = 'center';
- yAlign = yf(y);
- }
+ if (doesNotFitWithAlign(xAlign, chart, options, size)) {
+ xAlign = 'center';
}
+ return xAlign;
+}
+
+/**
+ * Helper to get the alignment of a tooltip given the size
+ */
+function determineAlignment(chart, options, size) {
+ const yAlign = options.yAlign || determineYAlign(chart, size);
+
return {
- xAlign: options.xAlign ? options.xAlign : xAlign,
- yAlign: options.yAlign ? options.yAlign : yAlign
+ xAlign: options.xAlign || determineXAlign(chart, options, size, yAlign),
+ yAlign
};
}
-function alignX(size, xAlign, chartWidth) {
- // eslint-disable-next-line prefer-const
+function alignX(size, xAlign) {
let {x, width} = size;
if (xAlign === 'right') {
x -= width;
} else if (xAlign === 'center') {
x -= (width / 2);
- if (x + width > chartWidth) {
- x = chartWidth - width;
- }
- if (x < 0) {
- x = 0;
- }
}
return x;
}
const paddingAndSize = caretSize + caretPadding;
const radiusAndPadding = cornerRadius + caretPadding;
- let x = alignX(size, xAlign, chart.width);
+ let x = alignX(size, xAlign);
const y = alignY(size, yAlign, paddingAndSize);
if (yAlign === 'center') {
x += radiusAndPadding;
}
- return {x, y};
+ return {
+ x: _limitValue(x, 0, chart.width - size.width),
+ y: _limitValue(y, 0, chart.height - size.height)
+ };
}
function getAlignedX(tooltip, align, options) {
--- /dev/null
+const data = [];
+for (let x = 0; x < 3; x++) {
+ for (let y = 0; y < 3; y++) {
+ data.push({x, y});
+ }
+}
+
+module.exports = {
+ config: {
+ type: 'scatter',
+ data: {
+ datasets: [{
+ data,
+ backgroundColor: 'red',
+ radius: 8
+ }],
+ },
+ options: {
+ scales: {
+ x: {display: false},
+ y: {display: false}
+ },
+ plugins: {
+ legend: false,
+ title: false,
+ filler: false,
+ tooltip: {
+ mode: 'point',
+ intersect: true,
+ // spriteText: use white background to hide any gaps between fonts
+ backgroundColor: 'white',
+ borderColor: 'black',
+ borderWidth: 1,
+ callbacks: {
+ beforeLabel: () => 'before label',
+ label: () => 'label',
+ afterLabel: () => 'after1\nafter2\nafter3\nafter4\nafter5'
+ }
+ }
+ },
+ },
+ plugins: [{
+ afterDraw: function(chart) {
+ const canvas = chart.canvas;
+ const rect = canvas.getBoundingClientRect();
+ const meta = chart.getDatasetMeta(0);
+ let point, event;
+
+ for (let i = 0; i < data.length; i++) {
+ point = meta.data[i];
+ event = {
+ type: 'mousemove',
+ target: canvas,
+ clientX: rect.left + point.x,
+ clientY: rect.top + point.y
+ };
+ chart._handleEvent(event);
+ chart.tooltip.handleEvent(event);
+ chart.tooltip.draw(chart.ctx);
+ }
+ }
+ }]
+ },
+ options: {
+ spriteText: true,
+ canvas: {
+ height: 400,
+ width: 500
+ }
+ }
+};