From d26ab24e3c03180c8a76332e3ed86dd139e3594d Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Mon, 21 Dec 2015 15:52:19 -0500 Subject: [PATCH 1/4] Show rectangle points at end of bars, even negative ones. --- src/elements/element.rectangle.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/elements/element.rectangle.js b/src/elements/element.rectangle.js index 0e361cba691..1de5b16f3e1 100644 --- a/src/elements/element.rectangle.js +++ b/src/elements/element.rectangle.js @@ -78,17 +78,10 @@ }, tooltipPosition: function() { var vm = this._view; - if (vm.y < vm.base) { - return { - x: vm.x, - y: vm.y - }; - } else { - return { - x: vm.x, - y: vm.base - }; - } + return { + x: vm.x, + y: vm.y + }; }, }); From d7643bf865def6090cea9ef5b0ade7844c1d5477 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Mon, 21 Dec 2015 15:52:33 -0500 Subject: [PATCH 2/4] Initial refactor of tooltip code --- src/core/core.tooltip.js | 318 ++++++++++++++++++++------------------- 1 file changed, 161 insertions(+), 157 deletions(-) diff --git a/src/core/core.tooltip.js b/src/core/core.tooltip.js index dfd5d704b0a..3fdc54d17bc 100644 --- a/src/core/core.tooltip.js +++ b/src/core/core.tooltip.js @@ -297,227 +297,231 @@ return this; }, - draw: function() { - - - var ctx = this._chart.ctx; + getTooltipSize: function getTooltipSize() { var vm = this._view; + var ctx = this._chart.ctx; - if (this._view.opacity === 0) { - return; - } - - // Get Dimensions - - vm.position = "top"; - - var caretPadding = vm.caretPadding || 2; - + var size = { + height: vm.yPadding * 2, // Tooltip Padding + width: 0 + }; var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length; - // Height - var tooltipHeight = vm.yPadding * 2; // Tooltip Padding - - tooltipHeight += vm.title.length * vm.titleFontSize; // Title Lines - tooltipHeight += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing - tooltipHeight += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin - - tooltipHeight += combinedBodyLength * vm.bodyFontSize; // Body Lines - tooltipHeight += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing - - tooltipHeight += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin - tooltipHeight += vm.footer.length * (vm.footerFontSize); // Footer Lines - tooltipHeight += vm.footer.length ? (vm.footer.length - 1) * vm.footerSpacing : 0; // Footer Line Spacing + size.height += vm.title.length * vm.titleFontSize; // Title Lines + size.height += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing + size.height += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin + size.height += combinedBodyLength * vm.bodyFontSize; // Body Lines + size.height += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing + size.height += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin + size.height += vm.footer.length * (vm.footerFontSize); // Footer Lines + size.height += vm.footer.length ? (vm.footer.length - 1) * vm.footerSpacing : 0; // Footer Line Spacing // Width - var tooltipWidth = 0; + ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily); helpers.each(vm.title, function(line) { - ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily); - tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width); + size.width = Math.max(size.width, ctx.measureText(line).width); }); - helpers.each(vm.beforeBody, function(line) { - ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); - tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width); + + ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); + helpers.each(vm.beforeBody.concat(vm.afterBody), function(line) { + size.width = Math.max(size.width, ctx.measureText(line).width); }, this); helpers.each(vm.body, function(line) { - ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); - tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0)); - }, this); - helpers.each(vm.afterBody, function(line) { - ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); - tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width); + size.width = Math.max(size.width, ctx.measureText(line).width + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0)); }, this); + + ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); helpers.each(vm.footer, function(line) { - ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); - tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width); + size.width = Math.max(size.width, ctx.measureText(line).width); }); - tooltipWidth += 2 * vm.xPadding; - var tooltipTotalWidth = tooltipWidth + vm.caretSize + caretPadding; - + size.width += 2 * vm.xPadding; - - // Smart Tooltip placement to stay on the canvas - // Top, center, or bottom + return size; + }, + determineAlignment: function determineAlignment(size) { + var vm = this._view; vm.yAlign = "center"; - if (vm.y - (tooltipHeight / 2) < 0) { + if (vm.y - (size.height / 2) < 0) { vm.yAlign = "top"; - } else if (vm.y + (tooltipHeight / 2) > this._chart.height) { + } else if (vm.y + (size.height / 2) > this._chart.height) { vm.yAlign = "bottom"; } - // Left or Right vm.xAlign = "right"; - if (vm.x + tooltipTotalWidth > this._chart.width) { + if (vm.x + size.width > this._chart.width) { vm.xAlign = "left"; } - - + }, + getBackgroundPoint: function getBackgroundPoint(size, caretPadding) { + var vm = this._view; // Background Position - var tooltipX = vm.x, - tooltipY = vm.y; + var pt = { + x: vm.x, + y: vm.y + }; if (vm.yAlign === 'top') { - tooltipY = vm.y - vm.caretSize - vm.cornerRadius; + pt.y = vm.y - vm.caretSize - vm.cornerRadius; } else if (vm.yAlign === 'bottom') { - tooltipY = vm.y - tooltipHeight + vm.caretSize + vm.cornerRadius; + pt.y = vm.y - size.height + vm.caretSize + vm.cornerRadius; } else { - tooltipY = vm.y - (tooltipHeight / 2); + pt.y = vm.y - (size.height / 2); } if (vm.xAlign === 'left') { - tooltipX = vm.x - tooltipTotalWidth; + pt.x = vm.x - size.width; } else if (vm.xAlign === 'right') { - tooltipX = vm.x + caretPadding + vm.caretSize; + pt.x = vm.x + caretPadding + vm.caretSize; } else { - tooltipX = vm.x + (tooltipTotalWidth / 2); + pt.x = vm.x + (size.width / 2); } - // Draw Background + return pt; + }, + drawCaret: function drawCaret(opacity, caretPadding) { + var vm = this._view; + var ctx = this._chart.ctx; - // IE11/Edge does not like very small opacities, so snap to 0 - var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity; + ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString(); + ctx.beginPath(); - if (this._options.tooltips.enabled) { - ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString(); - helpers.drawRoundedRectangle(ctx, tooltipX, tooltipY, tooltipWidth, tooltipHeight, vm.cornerRadius); - ctx.fill(); + if (vm.xAlign === 'left') { + ctx.moveTo(vm.x - caretPadding, vm.y); + ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y - vm.caretSize); + ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y + vm.caretSize); + } else { + ctx.moveTo(vm.x + caretPadding, vm.y); + ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y - vm.caretSize); + ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y + vm.caretSize); } + ctx.closePath(); + ctx.fill(); + }, + drawTitle: function drawTitle(pt, vm, ctx, opacity) { + if (vm.title.length) { + ctx.textAlign = vm._titleAlign; + ctx.textBaseline = "top"; + ctx.fillStyle = helpers.color(vm.titleColor).alpha(opacity).rgbString(); + ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily); - // Draw Caret - if (this._options.tooltips.enabled) { - ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString(); - - if (vm.xAlign === 'left') { - - ctx.beginPath(); - ctx.moveTo(vm.x - caretPadding, vm.y); - ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y - vm.caretSize); - ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y + vm.caretSize); - ctx.closePath(); - ctx.fill(); - } else { - ctx.beginPath(); - ctx.moveTo(vm.x + caretPadding, vm.y); - ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y - vm.caretSize); - ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y + vm.caretSize); - ctx.closePath(); - ctx.fill(); - } + helpers.each(vm.title, function(title, i) { + ctx.fillText(title, pt.x, pt.y); + pt.y += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing + + if (i + 1 === vm.title.length) { + pt.y += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing + } + }, this); } + }, + drawBody: function drawBody(pt, vm, ctx, opacity) { + ctx.textAlign = vm._bodyAlign; + ctx.textBaseline = "top"; + ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbString(); + ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); + + // Before Body + helpers.each(vm.beforeBody, function(beforeBody) { + ctx.fillText(beforeBody, pt.x, pt.y); + pt.y += vm.bodyFontSize + vm.bodySpacing; + }); - // Draw Title, Body, and Footer - - if (this._options.tooltips.enabled) { + helpers.each(vm.body, function(body, i) { + // Draw Legend-like boxes if needed + if (this._options.tooltips.mode !== 'single') { + // Fill a white rect so that colours merge nicely if the opacity is < 1 + ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString(); + ctx.fillRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize); - var yBase = tooltipY + vm.yPadding; - var xBase = tooltipX + vm.xPadding; + // Border + ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString(); + ctx.strokeRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize); - // Titles + // Inner square + ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString(); + ctx.fillRect(pt.x + 1, pt.y + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2); - if (vm.title.length) { - ctx.textAlign = vm._titleAlign; - ctx.textBaseline = "top"; - ctx.fillStyle = helpers.color(vm.titleColor).alpha(opacity).rgbString(); - ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily); - - helpers.each(vm.title, function(title, i) { - ctx.fillText(title, xBase, yBase); - yBase += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing - if (i + 1 === vm.title.length) { - yBase += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing - } - }, this); + ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text } + // Body Line + ctx.fillText(body, pt.x + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y); - // Body - ctx.textAlign = vm._bodyAlign; - ctx.textBaseline = "top"; - ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbString(); - ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); + pt.y += vm.bodyFontSize + vm.bodySpacing; + }, this); - // Before Body - helpers.each(vm.beforeBody, function(beforeBody) { - ctx.fillText(beforeBody, xBase, yBase); - yBase += vm.bodyFontSize + vm.bodySpacing; - }); + // After Body + helpers.each(vm.afterBody, function(afterBody) { + ctx.fillText(afterBody, pt.x, pt.y); + pt.y += vm.bodyFontSize; + }); - helpers.each(vm.body, function(body, i) { + pt.y -= vm.bodySpacing; // Remove last body spacing + }, + drawFooter: function drawFooter(pt, vm, ctx, opacity) { + if (vm.footer.length) { + pt.y += vm.footerMarginTop; + ctx.textAlign = vm._footerAlign; + ctx.textBaseline = "top"; + ctx.fillStyle = helpers.color(vm.footerColor).alpha(opacity).rgbString(); + ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); - // Draw Legend-like boxes if needed - if (this._options.tooltips.mode !== 'single') { - // Fill a white rect so that colours merge nicely if the opacity is < 1 - ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString(); - ctx.fillRect(xBase, yBase, vm.bodyFontSize, vm.bodyFontSize); + helpers.each(vm.footer, function(footer) { + ctx.fillText(footer, pt.x, pt.y); + pt.y += vm.footerFontSize + vm.footerSpacing; + }, this); + } + }, + draw: function draw() { + var ctx = this._chart.ctx; + var vm = this._view; - // Border - ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString(); - ctx.strokeRect(xBase, yBase, vm.bodyFontSize, vm.bodyFontSize); + if (vm.opacity === 0) { + return; + } - // Inner square - ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString(); - ctx.fillRect(xBase + 1, yBase + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2); + var caretPadding = vm.caretPadding || 2; + var tooltipSize = this.getTooltipSize(); + var backgroundWidth = tooltipSize.width; + + // Expand to be new total size (including caret) + tooltipSize.width += vm.caretSize + caretPadding; - ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text - } + // Smart Tooltip placement to stay on the canvas + // Top, center, or bottom + this.determineAlignment(tooltipSize); - // Body Line - ctx.fillText(body, xBase + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), yBase); + var pt = this.getBackgroundPoint(tooltipSize, caretPadding); - yBase += vm.bodyFontSize + vm.bodySpacing; + // IE11/Edge does not like very small opacities, so snap to 0 + var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity; - }, this); + if (this._options.tooltips.enabled) { + // Draw Background + ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString(); + helpers.drawRoundedRectangle(ctx, pt.x, pt.y, backgroundWidth, tooltipSize.height, vm.cornerRadius); + ctx.fill(); - // After Body - helpers.each(vm.afterBody, function(afterBody) { - ctx.fillText(afterBody, xBase, yBase); - yBase += vm.bodyFontSize; - }); + // Draw Caret + this.drawCaret(opacity, caretPadding); + + // Draw Title, Body, and Footer + pt.x += vm.xPadding; + pt.y += vm.yPadding; - yBase -= vm.bodySpacing; // Remove last body spacing + // Titles + this.drawTitle(pt, vm, ctx, opacity); + // Body + this.drawBody(pt, vm, ctx, opacity); // Footer - if (vm.footer.length) { - - yBase += vm.footerMarginTop; - - ctx.textAlign = vm._footerAlign; - ctx.textBaseline = "top"; - ctx.fillStyle = helpers.color(vm.footerColor).alpha(opacity).rgbString(); - ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); - - helpers.each(vm.footer, function(footer) { - ctx.fillText(footer, xBase, yBase); - yBase += vm.footerFontSize + vm.footerSpacing; - }, this); - } - + this.drawFooter(pt, vm, ctx, opacity); } - }, + } }); }).call(this); From f170fd1b8d73427e8f1762d252101c6f44b0d5f8 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Tue, 22 Dec 2015 21:35:23 -0500 Subject: [PATCH 3/4] Improvements to tooltip alignment to avoid the canvas edges --- src/core/core.controller.js | 1 + src/core/core.tooltip.js | 153 +++++++++++++++++++++++++----------- 2 files changed, 106 insertions(+), 48 deletions(-) diff --git a/src/core/core.controller.js b/src/core/core.controller.js index d57ebcc8aa3..17b875c5e55 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -400,6 +400,7 @@ initToolTip: function initToolTip() { this.tooltip = new Chart.Tooltip({ _chart: this.chart, + _chartInstance: this, _data: this.data, _options: this.options, }, this); diff --git a/src/core/core.tooltip.js b/src/core/core.tooltip.js index 3fdc54d17bc..10cef30b4be 100644 --- a/src/core/core.tooltip.js +++ b/src/core/core.tooltip.js @@ -283,9 +283,15 @@ helpers.extend(this._model, { x: Math.round(tooltipPosition.x), y: Math.round(tooltipPosition.y), - caretPadding: tooltipPosition.padding, + caretPadding: helpers.getValueOrDefault(tooltipPosition.padding, 2), labelColors: labelColors, }); + + // We need to determine alignment of + var tooltipSize = this.getTooltipSize(this._model); + this.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas + + helpers.extend(this._model, this.getBackgroundPoint(this._model, tooltipSize)); } else{ this._model.opacity = 0; @@ -297,8 +303,7 @@ return this; }, - getTooltipSize: function getTooltipSize() { - var vm = this._view; + getTooltipSize: function getTooltipSize(vm) { var ctx = this._chart.ctx; var size = { @@ -339,63 +344,121 @@ return size; }, determineAlignment: function determineAlignment(size) { - var vm = this._view; - vm.yAlign = "center"; - if (vm.y - (size.height / 2) < 0) { - vm.yAlign = "top"; - } else if (vm.y + (size.height / 2) > this._chart.height) { - vm.yAlign = "bottom"; + this._model.xAlign = this._model.yAlign = "center"; + + if (this._model.y < size.height) { + this._model.yAlign = 'top'; + } else if (this._model.y > (this._chart.height - size.height)) { + this._model.yAlign = 'bottom'; + } + + var lf, rf; + var _this = this; + var midX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2; + + if (this._model.yAlign === 'center') { + lf = function(x) { return x <= midX; }; + rf = function(x) { return x > midX; }; + } else { + lf = function(x) { return x <= (size.width / 2); }; + rf = function(x) { return x >= (_this._chart.width - (size.width / 2)); }; } - // Left or Right - vm.xAlign = "right"; - if (vm.x + size.width > this._chart.width) { - vm.xAlign = "left"; + if (lf(this._model.x)) { + this._model.xAlign = 'left'; + } else if (rf(this._model.x)) { + this._model.xAlign = 'right'; } }, - getBackgroundPoint: function getBackgroundPoint(size, caretPadding) { - var vm = this._view; + getBackgroundPoint: function getBackgroundPoint(vm, size) { // Background Position var pt = { x: vm.x, y: vm.y }; + if (vm.xAlign === 'right') { + pt.x -= size.width; + } else if (vm.xAlign === 'center') { + pt.x -= (size.width / 2); + } + if (vm.yAlign === 'top') { - pt.y = vm.y - vm.caretSize - vm.cornerRadius; + pt.y += vm.caretPadding + vm.caretSize; } else if (vm.yAlign === 'bottom') { - pt.y = vm.y - size.height + vm.caretSize + vm.cornerRadius; + pt.y -= size.height + vm.caretPadding + vm.caretSize; } else { - pt.y = vm.y - (size.height / 2); + pt.y -= (size.height / 2); } - if (vm.xAlign === 'left') { - pt.x = vm.x - size.width; - } else if (vm.xAlign === 'right') { - pt.x = vm.x + caretPadding + vm.caretSize; + if (vm.yAlign == 'center') { + if (vm.xAlign === 'left') { + pt.x += vm.caretPadding + vm.caretSize; + } else if (vm.xAlign === 'right') { + pt.x -= vm.caretPadding + vm.caretSize; + } } else { - pt.x = vm.x + (size.width / 2); + if (vm.xAlign === 'left') { + pt.x -= vm.cornerRadius + vm.caretPadding; + } else if (vm.xAlign === 'right') { + pt.x += vm.cornerRadius + vm.caretPadding; + } } return pt; }, - drawCaret: function drawCaret(opacity, caretPadding) { + drawCaret: function drawCaret(tooltipPoint, size, opacity, caretPadding) { var vm = this._view; var ctx = this._chart.ctx; + var x1, x2, x3; + var y1, y2, y3; + + if (vm.yAlign === 'center') { + // Left or right side + if (vm.xAlign === 'left') { + x1 = tooltipPoint.x; + x2 = x1 - vm.caretSize; + x3 = x1; + } else { + x1 = tooltipPoint.x + size.width; + x2 = x1 + vm.caretSize; + x3 = x1; + } - ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString(); - ctx.beginPath(); - - if (vm.xAlign === 'left') { - ctx.moveTo(vm.x - caretPadding, vm.y); - ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y - vm.caretSize); - ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y + vm.caretSize); + y2 = tooltipPoint.y + (size.height / 2); + y1 = y2 - vm.caretSize; + y3 = y2 + vm.caretSize; } else { - ctx.moveTo(vm.x + caretPadding, vm.y); - ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y - vm.caretSize); - ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y + vm.caretSize); + if (vm.xAlign === 'left') { + x1 = tooltipPoint.x + vm.cornerRadius; + x2 = x1 + vm.caretSize; + x3 = x2 + vm.caretSize; + } else if (vm.xAlign === 'right') { + x1 = tooltipPoint.x + size.width - vm.cornerRadius; + x2 = x1 - vm.caretSize; + x3 = x2 - vm.caretSize; + } else { + x2 = tooltipPoint.x + (size.width / 2); + x1 = x2 - vm.caretSize; + x3 = x2 + vm.caretSize; + } + + if (vm.yAlign === 'top') { + y1 = tooltipPoint.y; + y2 = y1 - vm.caretSize; + y3 = y1; + } else { + y1 = tooltipPoint.y + size.height; + y2 = y1 + vm.caretSize; + y3 = y1; + } } + ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString(); + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x3, y3); ctx.closePath(); ctx.fill(); }, @@ -483,18 +546,12 @@ return; } - var caretPadding = vm.caretPadding || 2; - var tooltipSize = this.getTooltipSize(); - var backgroundWidth = tooltipSize.width; - - // Expand to be new total size (including caret) - tooltipSize.width += vm.caretSize + caretPadding; - - // Smart Tooltip placement to stay on the canvas - // Top, center, or bottom - this.determineAlignment(tooltipSize); - - var pt = this.getBackgroundPoint(tooltipSize, caretPadding); + var caretPadding = vm.caretPadding; + var tooltipSize = this.getTooltipSize(vm); + var pt = { + x: vm.x, + y: vm.y + }; // IE11/Edge does not like very small opacities, so snap to 0 var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity; @@ -502,11 +559,11 @@ if (this._options.tooltips.enabled) { // Draw Background ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString(); - helpers.drawRoundedRectangle(ctx, pt.x, pt.y, backgroundWidth, tooltipSize.height, vm.cornerRadius); + helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius); ctx.fill(); // Draw Caret - this.drawCaret(opacity, caretPadding); + this.drawCaret(pt, tooltipSize, opacity, caretPadding); // Draw Title, Body, and Footer pt.x += vm.xPadding; From bbc6f5aa5fdcfd1be9def2787ecddc3003babcba Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Wed, 23 Dec 2015 12:00:56 -0500 Subject: [PATCH 4/4] Fix broken test --- test/element.rectangle.tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/element.rectangle.tests.js b/test/element.rectangle.tests.js index f8bd51efd55..cb1959b0455 100644 --- a/test/element.rectangle.tests.js +++ b/test/element.rectangle.tests.js @@ -109,7 +109,7 @@ describe('Rectangle element tests', function() { expect(rectangle.tooltipPosition()).toEqual({ x: 10, - y: 0, + y: 15, }); // Test when the y is below the base (negative bar)