]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
External Tooltips, Documentation, and Samples
authorTanner Linsley <tannerlinsley@gmail.com>
Tue, 30 Dec 2014 17:51:10 +0000 (10:51 -0700)
committerTanner Linsley <tannerlinsley@gmail.com>
Tue, 30 Dec 2014 20:05:11 +0000 (13:05 -0700)
docs/00-Getting-Started.md
docs/06-Advanced.md
samples/line-externalTooltips.html [new file with mode: 0644]
samples/pie-externalTooltips.html [new file with mode: 0644]
src/Chart.Core.js

index 74287a94c28d5ac63798a190a04bc1343dadd7f0..7cb1097aa7c049bb53644b6e2ff499014144ab30 100644 (file)
@@ -132,6 +132,9 @@ Chart.defaults.global = {
        // 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"],
 
index f9d696da28b418db6acda41aaa287e70f350e797..d6cbf3a031df0b06c69e5caf7cfffa2dd3b3b557 100644 (file)
@@ -70,6 +70,39 @@ myLineChart.generateLegend();
 // => 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.
diff --git a/samples/line-externalTooltips.html b/samples/line-externalTooltips.html
new file mode 100644 (file)
index 0000000..67eab85
--- /dev/null
@@ -0,0 +1,129 @@
+<!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>
diff --git a/samples/pie-externalTooltips.html b/samples/pie-externalTooltips.html
new file mode 100644 (file)
index 0000000..c126c64
--- /dev/null
@@ -0,0 +1,156 @@
+<!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>
index 03b99b45a582e69ae57ea79f3ed3e5bbae3bb0d1..07c63c4d5a27634141d544d90093c5f26162cae3 100755 (executable)
@@ -98,6 +98,9 @@
                        // 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);
+                       }
                }
        });