// Boolean - Determines whether to draw tooltips on the canvas or not
showTooltips: true,
+ // Function - Determines whether to execute the externalTooltips function instead of drawing the built in tooltips (See [Advanced - External Tooltips](#advanced-usage-external-tooltips))
+ externalTooltips: false,
+
// Array - Array of string names to attach tooltip events
tooltipEvents: ["mousemove", "touchstart", "touchmove"],
// => returns HTML string of a legend for this chart
```
+### External Tooltips
+
+You can enable external tooltips in the global or chart configuration like so:
+
+```javascript
+var myPieChart = new Chart(ctx).Pie(data, {
+ externalTooltips: function(tooltip) {
+
+ // tooltip will be false if tooltip is not visible or should be hidden
+ if (!tooltip) {
+ return;
+ }
+
+ // Otherwise, tooltip will be an object with all tooltip properties like:
+
+ // tooltip.caretHeight
+ // tooltip.caretPadding
+ // tooltip.chart
+ // tooltip.cornerRadius
+ // tooltip.fillColor
+ // tooltip.font...
+ // tooltip.text
+ // tooltip.x
+ // tooltip.y
+ // etc...
+
+ };
+});
+```
+
+See files `sample/pie-externalTooltips.html` and `sample/line-externalTooltips.html` for examples on how to get started.
+
+
### Writing new chart types
Chart.js 1.0 has been rewritten to provide a platform for developers to create their own custom chart types, and be able to share and utilise them through the Chart.js API.
--- /dev/null
+<!doctype html>
+<html>
+
+<head>
+ <title>Line Chart with Custom Tooltips</title>
+ <script src="../Chart.js"></script>
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+
+ <style>
+ #canvas-holder1 {
+ width: 300px;
+ margin: 20px auto;
+ }
+ #canvas-holder2 {
+ width: 50%;
+ margin: 20px 25%;
+ }
+ #chartjs-tooltip {
+ opacity: 1;
+ position: absolute;
+ background: rgba(0, 0, 0, .7);
+ color: white;
+ padding: 3px;
+ border-radius: 3px;
+ -webkit-transition: all .1s ease;
+ transition: all .1s ease;
+ pointer-events: none;
+ -webkit-transform: translate(-50%, 0);
+ transform: translate(-50%, 0);
+ }
+ .chartjs-tooltip-key{
+ display:inline-block;
+ width:10px;
+ height:10px;
+ }
+ </style>
+</head>
+
+<body>
+ <div id="canvas-holder1">
+ <canvas id="chart1" width="300" height="30" />
+ </div>
+ <div id="canvas-holder2">
+ <canvas id="chart2" width="450" height="600" />
+ </div>
+
+ <div id="chartjs-tooltip"></div>
+
+
+ <script>
+
+ Chart.defaults.global.pointHitDetectionRadius = 1;
+ Chart.defaults.global.externalTooltips = function(tooltip) {
+
+ var tooltipEl = $('#chartjs-tooltip');
+
+ if (!tooltip) {
+ tooltipEl.css({
+ opacity: 0
+ });
+ return;
+ }
+
+ tooltipEl.removeClass('above below');
+ tooltipEl.addClass(tooltip.yAlign);
+
+ var innerHtml = '';
+ for (var i = tooltip.labels.length - 1; i >= 0; i--) {
+ innerHtml += [
+ '<div class="chartjs-tooltip-section">',
+ ' <span class="chartjs-tooltip-key" style="background-color:' + tooltip.legendColors[i].fill + '"></span>',
+ ' <span class="chartjs-tooltip-value">' + tooltip.labels[i] + '</span>',
+ '</div>'
+ ].join('');
+ }
+ tooltipEl.html(innerHtml);
+
+ tooltipEl.css({
+ opacity: 1,
+ left: tooltip.chart.canvas.offsetLeft + tooltip.x + 'px',
+ top: tooltip.chart.canvas.offsetTop + tooltip.y + 'px',
+ fontFamily: tooltip.fontFamily,
+ fontSize: tooltip.fontSize,
+ fontStyle: tooltip.fontStyle,
+ });
+ };
+ var randomScalingFactor = function() {
+ return Math.round(Math.random() * 100);
+ };
+ var lineChartData = {
+ labels: ["January", "February", "March", "April", "May", "June", "July"],
+ datasets: [{
+ label: "My First dataset",
+ fillColor: "rgba(220,220,220,0.2)",
+ strokeColor: "rgba(220,220,220,1)",
+ pointColor: "rgba(220,220,220,1)",
+ pointStrokeColor: "#fff",
+ pointHighlightFill: "#fff",
+ pointHighlightStroke: "rgba(220,220,220,1)",
+ data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
+ }, {
+ label: "My Second dataset",
+ fillColor: "rgba(151,187,205,0.2)",
+ strokeColor: "rgba(151,187,205,1)",
+ pointColor: "rgba(151,187,205,1)",
+ pointStrokeColor: "#fff",
+ pointHighlightFill: "#fff",
+ pointHighlightStroke: "rgba(151,187,205,1)",
+ data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
+ }]
+ };
+
+ window.onload = function() {
+ var ctx1 = document.getElementById("chart1").getContext("2d");
+ window.myLine = new Chart(ctx1).Line(lineChartData, {
+ showScale: false,
+ pointDot : true,
+ responsive: true
+ });
+
+ var ctx2 = document.getElementById("chart2").getContext("2d");
+ window.myLine = new Chart(ctx2).Line(lineChartData, {
+ responsive: true
+ });
+ };
+ </script>
+</body>
+
+</html>
--- /dev/null
+<!doctype html>
+<html>
+
+<head>
+ <title>Pie Chart with Custom Tooltips</title>
+ <script src="../Chart.js"></script>
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+
+ <style>
+ #canvas-holder {
+ width: 100%;
+ margin-top: 50px;
+ text-align: center;
+ }
+ #chartjs-tooltip {
+ opacity: 1;
+ position: absolute;
+ background: rgba(0, 0, 0, .7);
+ color: white;
+ padding: 3px;
+ border-radius: 3px;
+ -webkit-transition: all .1s ease;
+ transition: all .1s ease;
+ pointer-events: none;
+ -webkit-transform: translate(-50%, 0);
+ transform: translate(-50%, 0);
+ }
+ #chartjs-tooltip.below {
+ -webkit-transform: translate(-50%, 0);
+ transform: translate(-50%, 0);
+ }
+ #chartjs-tooltip.below:before {
+ border: solid;
+ border-color: #111 transparent;
+ border-color: rgba(0, 0, 0, .8) transparent;
+ border-width: 0 8px 8px 8px;
+ bottom: 1em;
+ content: "";
+ display: block;
+ left: 50%;
+ position: absolute;
+ z-index: 99;
+ -webkit-transform: translate(-50%, -100%);
+ transform: translate(-50%, -100%);
+ }
+ #chartjs-tooltip.above {
+ -webkit-transform: translate(-50%, -100%);
+ transform: translate(-50%, -100%);
+ }
+ #chartjs-tooltip.above:before {
+ border: solid;
+ border-color: #111 transparent;
+ border-color: rgba(0, 0, 0, .8) transparent;
+ border-width: 8px 8px 0 8px;
+ bottom: 1em;
+ content: "";
+ display: block;
+ left: 50%;
+ top: 100%;
+ position: absolute;
+ z-index: 99;
+ -webkit-transform: translate(-50%, 0);
+ transform: translate(-50%, 0);
+ }
+ </style>
+</head>
+
+<body>
+ <div id="canvas-holder">
+ <canvas id="chart-area1" width="50" height="50" />
+ </div>
+ <div id="canvas-holder">
+ <canvas id="chart-area2" width="300" height="300" />
+ </div>
+
+ <div id="chartjs-tooltip"></div>
+
+
+ <script>
+ Chart.defaults.global.externalTooltips = function(tooltip) {
+
+ // Tooltip Element
+ var tooltipEl = $('#chartjs-tooltip');
+
+ // Hide if no tooltip
+ if (!tooltip) {
+ tooltipEl.css({
+ opacity: 0
+ });
+ return;
+ }
+
+ // Set caret Position
+ tooltipEl.removeClass('above below');
+ tooltipEl.addClass(tooltip.yAlign);
+
+ // Set Text
+ tooltipEl.html(tooltip.text);
+
+ // Find Y Location on page
+ var top;
+ if (tooltip.yAlign == 'above') {
+ top = tooltip.y - tooltip.caretHeight - tooltip.caretPadding;
+ } else {
+ top = tooltip.y + tooltip.caretHeight + tooltip.caretPadding;
+ }
+
+ // Display, position, and set styles for font
+ tooltipEl.css({
+ opacity: 1,
+ left: tooltip.chart.canvas.offsetLeft + tooltip.x + 'px',
+ top: tooltip.chart.canvas.offsetTop + top + 'px',
+ fontFamily: tooltip.fontFamily,
+ fontSize: tooltip.fontSize,
+ fontStyle: tooltip.fontStyle,
+ });
+ };
+
+ var pieData = [{
+ value: 300,
+ color: "#F7464A",
+ highlight: "#FF5A5E",
+ label: "Red"
+ }, {
+ value: 50,
+ color: "#46BFBD",
+ highlight: "#5AD3D1",
+ label: "Green"
+ }, {
+ value: 100,
+ color: "#FDB45C",
+ highlight: "#FFC870",
+ label: "Yellow"
+ }, {
+ value: 40,
+ color: "#949FB1",
+ highlight: "#A8B3C5",
+ label: "Grey"
+ }, {
+ value: 120,
+ color: "#4D5360",
+ highlight: "#616774",
+ label: "Dark Grey"
+ }];
+
+ window.onload = function() {
+ var ctx1 = document.getElementById("chart-area1").getContext("2d");
+ window.myPie = new Chart(ctx1).Pie(pieData);
+
+ var ctx2 = document.getElementById("chart-area2").getContext("2d");
+ window.myPie = new Chart(ctx2).Pie(pieData);
+ };
+ </script>
+</body>
+
+</html>
// Boolean - Determines whether to draw tooltips on the canvas or not - attaches events to touchmove & mousemove
showTooltips: true,
+ // Boolean - Determines whether to draw built-in tooltip or call custom tooltip function
+ externalTooltips: false,
+
// Array - Array of string names to attach tooltip events
tooltipEvents: ["mousemove", "touchstart", "touchmove", "mouseout"],
this.activeElements = ChartElements;
}
this.draw();
+ if(this.options.externalTooltips){
+ this.options.externalTooltips(false);
+ }
if (ChartElements.length > 0){
// If we have multiple datasets, show a MultiTooltip for all of the data points at that index
if (this.datasets && this.datasets.length > 1) {
legendColorBackground : this.options.multiTooltipKeyBackground,
title: ChartElements[0].label,
chart: this.chart,
- ctx: this.chart.ctx
+ ctx: this.chart.ctx,
+ external: this.options.externalTooltips
}).draw();
} else {
caretHeight: this.options.tooltipCaretSize,
cornerRadius: this.options.tooltipCornerRadius,
text: template(this.options.tooltipTemplate, Element),
- chart: this.chart
+ chart: this.chart,
+ external: this.options.externalTooltips
}).draw();
}, this);
}
this.yAlign = "above";
//Distance between the actual element.y position and the start of the tooltip caret
- var caretPadding = 2;
+ var caretPadding = this.caretPadding = 2;
var tooltipWidth = ctx.measureText(this.text).width + 2*this.xPadding,
tooltipRectHeight = this.fontSize + 2*this.yPadding,
ctx.fillStyle = this.fillColor;
- switch(this.yAlign)
- {
- case "above":
- //Draw a caret above the x/y
- ctx.beginPath();
- ctx.moveTo(this.x,this.y - caretPadding);
- ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight));
- ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight));
- ctx.closePath();
- ctx.fill();
- break;
- case "below":
- tooltipY = this.y + caretPadding + this.caretHeight;
- //Draw a caret below the x/y
- ctx.beginPath();
- ctx.moveTo(this.x, this.y + caretPadding);
- ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight);
- ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight);
- ctx.closePath();
- ctx.fill();
- break;
+ // Custom Tooltips
+ if(this.external){
+ this.external(this);
}
+ else{
+ switch(this.yAlign)
+ {
+ case "above":
+ //Draw a caret above the x/y
+ ctx.beginPath();
+ ctx.moveTo(this.x,this.y - caretPadding);
+ ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight));
+ ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight));
+ ctx.closePath();
+ ctx.fill();
+ break;
+ case "below":
+ tooltipY = this.y + caretPadding + this.caretHeight;
+ //Draw a caret below the x/y
+ ctx.beginPath();
+ ctx.moveTo(this.x, this.y + caretPadding);
+ ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight);
+ ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight);
+ ctx.closePath();
+ ctx.fill();
+ break;
+ }
- switch(this.xAlign)
- {
- case "left":
- tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight);
- break;
- case "right":
- tooltipX = this.x - (this.cornerRadius + this.caretHeight);
- break;
- }
+ switch(this.xAlign)
+ {
+ case "left":
+ tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight);
+ break;
+ case "right":
+ tooltipX = this.x - (this.cornerRadius + this.caretHeight);
+ break;
+ }
- drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius);
+ drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius);
- ctx.fill();
+ ctx.fill();
- ctx.fillStyle = this.textColor;
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2);
+ ctx.fillStyle = this.textColor;
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2);
+ }
}
});
},
draw : function(){
- drawRoundedRectangle(this.ctx,this.x,this.y - this.height/2,this.width,this.height,this.cornerRadius);
- var ctx = this.ctx;
- ctx.fillStyle = this.fillColor;
- ctx.fill();
- ctx.closePath();
+ // Custom Tooltips
+ if(this.external){
+ this.external(this);
+ }
+ else{
+ drawRoundedRectangle(this.ctx,this.x,this.y - this.height/2,this.width,this.height,this.cornerRadius);
+ var ctx = this.ctx;
+ ctx.fillStyle = this.fillColor;
+ ctx.fill();
+ ctx.closePath();
- ctx.textAlign = "left";
- ctx.textBaseline = "middle";
- ctx.fillStyle = this.titleTextColor;
- ctx.font = this.titleFont;
+ ctx.textAlign = "left";
+ ctx.textBaseline = "middle";
+ ctx.fillStyle = this.titleTextColor;
+ ctx.font = this.titleFont;
- ctx.fillText(this.title,this.x + this.xPadding, this.getLineHeight(0));
+ ctx.fillText(this.title,this.x + this.xPadding, this.getLineHeight(0));
- ctx.font = this.font;
- helpers.each(this.labels,function(label,index){
- ctx.fillStyle = this.textColor;
- ctx.fillText(label,this.x + this.xPadding + this.fontSize + 3, this.getLineHeight(index + 1));
+ ctx.font = this.font;
+ helpers.each(this.labels,function(label,index){
+ ctx.fillStyle = this.textColor;
+ ctx.fillText(label,this.x + this.xPadding + this.fontSize + 3, this.getLineHeight(index + 1));
- //A bit gnarly, but clearing this rectangle breaks when using explorercanvas (clears whole canvas)
- //ctx.clearRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
- //Instead we'll make a white filled block to put the legendColour palette over.
+ //A bit gnarly, but clearing this rectangle breaks when using explorercanvas (clears whole canvas)
+ //ctx.clearRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
+ //Instead we'll make a white filled block to put the legendColour palette over.
- ctx.fillStyle = this.legendColorBackground;
- ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
+ ctx.fillStyle = this.legendColorBackground;
+ ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
- ctx.fillStyle = this.legendColors[index].fill;
- ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
+ ctx.fillStyle = this.legendColors[index].fill;
+ ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
- },this);
+ },this);
+ }
}
});