]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Issue #2252, added usePointStyle option to allow label boxes to match the shape(point...
authorunknown <slinhart@knights.ucf.edu>
Sun, 3 Jul 2016 19:55:43 +0000 (13:55 -0600)
committerunknown <slinhart@knights.ucf.edu>
Sun, 3 Jul 2016 19:55:43 +0000 (13:55 -0600)
docs/01-Chart-Configuration.md
src/chart.js
src/core/core.canvasHelpers.js [new file with mode: 0644]
src/core/core.legend.js
src/elements/element.point.js
test/core.legend.tests.js
test/element.point.tests.js

index f2be7e3c25343433fec3431f2468614c61e77300..a573c51ff120b42b31867bde2b9845f8c3d5346e 100644 (file)
@@ -132,6 +132,7 @@ fontColor | Color | "#666" | Font color inherited from global configuration
 fontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Font family inherited from global configuration
 padding | Number | 10 | Padding between rows of colored boxes
 generateLabels: | Function | `function(chart) {  }` | Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. See [Legend Item](#chart-configuration-legend-item-interface) for details.
+usePointStyle | Boolean | false | Label style will match corresponding point style (size is based on fontSize, boxWidth is not used in this case).
 
 #### Legend Item Interface
 
@@ -165,6 +166,9 @@ Items passed to the legend `onClick` function are the ones returned from `labels
 
     // Stroke style of the legend box
     strokeStyle: Color
+
+    // Point style of the legend box (only used if usePointStyle is true)
+    pointStyle: String
 }
 ```
 
index 75bd47538416d3e9336a1b4ec48de02ac0eea19d..a12890aa06b96f1a79d7df094359f8a6694375af 100644 (file)
@@ -4,6 +4,7 @@
 var Chart = require('./core/core.js')();
 
 require('./core/core.helpers')(Chart);
+require('./core/core.canvasHelpers')(Chart);
 require('./core/core.element')(Chart);
 require('./core/core.animation')(Chart);
 require('./core/core.controller')(Chart);
diff --git a/src/core/core.canvasHelpers.js b/src/core/core.canvasHelpers.js
new file mode 100644 (file)
index 0000000..f8c35c9
--- /dev/null
@@ -0,0 +1,104 @@
+"use strict";
+
+module.exports = function(Chart) {
+       // Global Chart canvas helpers object for drawing items to canvas
+       var helpers = Chart.canvasHelpers = {};
+
+       helpers.drawPoint = function(ctx, pointStyle, radius, x, y) {
+               var type, edgeLength, xOffset, yOffset, height, size;
+
+               if (typeof pointStyle === 'object') {
+                       type = pointStyle.toString();
+                       if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
+                               ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2);
+                               return;
+                       }
+               }
+
+               if (isNaN(radius) || radius <= 0) {
+                       return;
+               }
+
+               switch (pointStyle) {
+               // Default includes circle
+               default:
+                       ctx.beginPath();
+                       ctx.arc(x, y, radius, 0, Math.PI * 2);
+                       ctx.closePath();
+                       ctx.fill();
+                       break;
+               case 'triangle':
+                       ctx.beginPath();
+                       edgeLength = 3 * radius / Math.sqrt(3);
+                       height = edgeLength * Math.sqrt(3) / 2;
+                       ctx.moveTo(x - edgeLength / 2, y + height / 3);
+                       ctx.lineTo(x + edgeLength / 2, y + height / 3);
+                       ctx.lineTo(x, y - 2 * height / 3);
+                       ctx.closePath();
+                       ctx.fill();
+                       break;
+               case 'rect':
+                       size = 1 / Math.SQRT2 * radius;
+                       ctx.beginPath();
+                       ctx.fillRect(x - size, y - size, 2 * size,  2 * size);
+                       ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
+                       break;
+               case 'rectRot':
+                       size = 1 / Math.SQRT2 * radius;
+                       ctx.beginPath();
+                       ctx.moveTo(x - size, y);
+                       ctx.lineTo(x, y + size);
+                       ctx.lineTo(x + size, y);
+                       ctx.lineTo(x, y - size);
+                       ctx.closePath();
+                       ctx.fill();
+                       break;
+               case 'cross':
+                       ctx.beginPath();
+                       ctx.moveTo(x, y + radius);
+                       ctx.lineTo(x, y - radius);
+                       ctx.moveTo(x - radius, y);
+                       ctx.lineTo(x + radius, y);
+                       ctx.closePath();
+                       break;
+               case 'crossRot':
+                       ctx.beginPath();
+                       xOffset = Math.cos(Math.PI / 4) * radius;
+                       yOffset = Math.sin(Math.PI / 4) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.moveTo(x - xOffset, y + yOffset);
+                       ctx.lineTo(x + xOffset, y - yOffset);
+                       ctx.closePath();
+                       break;
+               case 'star':
+                       ctx.beginPath();
+                       ctx.moveTo(x, y + radius);
+                       ctx.lineTo(x, y - radius);
+                       ctx.moveTo(x - radius, y);
+                       ctx.lineTo(x + radius, y);
+                       xOffset = Math.cos(Math.PI / 4) * radius;
+                       yOffset = Math.sin(Math.PI / 4) * radius;
+                       ctx.moveTo(x - xOffset, y - yOffset);
+                       ctx.lineTo(x + xOffset, y + yOffset);
+                       ctx.moveTo(x - xOffset, y + yOffset);
+                       ctx.lineTo(x + xOffset, y - yOffset);
+                       ctx.closePath();
+                       break;
+               case 'line':
+                       ctx.beginPath();
+                       ctx.moveTo(x - radius, y);
+                       ctx.lineTo(x + radius, y);
+                       ctx.closePath();
+                       break;
+               case 'dash':
+                       ctx.beginPath();
+                       ctx.moveTo(x, y);
+                       ctx.lineTo(x + radius, y);
+                       ctx.closePath();
+                       break;
+               }
+
+               ctx.stroke();
+       };
+};
\ No newline at end of file
index 78c89c55925262657d54aa3f39fc825512b81d8a..26e17f9914b0a9cacb81b5f8ef2e5ab7a2a4637d 100644 (file)
@@ -52,6 +52,7 @@ module.exports = function(Chart) {
                                                lineJoin: dataset.borderJoinStyle,
                                                lineWidth: dataset.borderWidth,
                                                strokeStyle: dataset.borderColor,
+                                               pointStyle: dataset.pointStyle,
 
                                                // Below is extra data used for toggling the datasets
                                                datasetIndex: i
@@ -201,7 +202,11 @@ module.exports = function(Chart) {
                                        ctx.textBaseline = 'top';
 
                                        helpers.each(me.legendItems, function(legendItem, i) {
-                                               var width = labelOpts.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+                                               var boxWidth = labelOpts.usePointStyle ?
+                                                       fontSize * Math.sqrt(2) :
+                                                       labelOpts.boxWidth;
+
+                                               var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
                                                if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
                                                        totalHeight += fontSize + (labelOpts.padding);
                                                        lineWidths[lineWidths.length] = me.left;
@@ -229,7 +234,11 @@ module.exports = function(Chart) {
                                        var itemHeight = fontSize + vPadding;
 
                                        helpers.each(me.legendItems, function(legendItem, i) {
-                                               var itemWidth = labelOpts.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+                                               // If usePointStyle is set, multiple boxWidth by 2 since it represents
+                                               // the radius and not truly the width
+                                               var boxWidth = labelOpts.usePointStyle ? 2 * labelOpts.boxWidth : labelOpts.boxWidth;
+
+                                               var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
 
                                                // If too tall, go to new column
                                                if (currentColHeight + itemHeight > minSize.height) {
@@ -303,6 +312,10 @@ module.exports = function(Chart) {
 
                                // current position
                                var drawLegendBox = function(x, y, legendItem) {
+                                       if (isNaN(boxWidth) || boxWidth <= 0) {
+                                               return;
+                                       }
+
                                        // Set the ctx for the box
                                        ctx.save();
 
@@ -318,9 +331,22 @@ module.exports = function(Chart) {
                                                ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash));
                                        }
 
-                                       // Draw the box
-                                       ctx.strokeRect(x, y, boxWidth, fontSize);
-                                       ctx.fillRect(x, y, boxWidth, fontSize);
+                                       if (opts.labels && opts.labels.usePointStyle) {
+                                               // Recalulate x and y for drawPoint() because its expecting
+                                               // x and y to be center of figure (instead of top left)
+                                               var radius = fontSize * Math.SQRT2 / 2;
+                                               var offSet = radius / Math.SQRT2;
+                                               var centerX = x + offSet;
+                                               var centerY = y + offSet;
+
+                                               // Draw pointStyle as legend symbol
+                                               Chart.canvasHelpers.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
+                                       }
+                                       else {
+                                               // Draw box as legend symbol
+                                               ctx.strokeRect(x, y, boxWidth, fontSize);
+                                               ctx.fillRect(x, y, boxWidth, fontSize);
+                                       }
 
                                        ctx.restore();
                                };
@@ -348,7 +374,7 @@ module.exports = function(Chart) {
                                } else {
                                        cursor = {
                                                x: me.left + labelOpts.padding,
-                                               y: me.top,
+                                               y: me.top + labelOpts.padding,
                                                line: 0
                                        };
                                }
@@ -356,13 +382,15 @@ module.exports = function(Chart) {
                                var itemHeight = fontSize + labelOpts.padding;
                                helpers.each(me.legendItems, function(legendItem, i) {
                                        var textWidth = ctx.measureText(legendItem.text).width,
-                                               width = boxWidth + (fontSize / 2) + textWidth,
+                                               width = labelOpts.usePointStyle ?
+                                                       fontSize + (fontSize / 2) + textWidth :
+                                                       boxWidth + (fontSize / 2) + textWidth,
                                                x = cursor.x,
                                                y = cursor.y;
 
                                        if (isHorizontal) {
                                                if (x + width >= legendWidth) {
-                                                       y = cursor.y += fontSize + (labelOpts.padding);
+                                                       y = cursor.y += itemHeight;
                                                        cursor.line++;
                                                        x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
                                                }
@@ -374,7 +402,6 @@ module.exports = function(Chart) {
                                                }
                                        }
                                        
-
                                        drawLegendBox(x, y, legendItem);
 
                                        hitboxes[i].left = x;
index 3290041b2b9abe390b1b2789b7cb24323ecfd52e..4131f8ceded7c2bc12dfd76ae116aaf92d9d42b4 100644 (file)
@@ -42,108 +42,16 @@ module.exports = function(Chart) {
                        var radius = vm.radius;
                        var x = vm.x;
                        var y = vm.y;
-                       var type, edgeLength, xOffset, yOffset, height, size;
 
                        if (vm.skip) {
                                return;
                        }
 
-                       if (typeof pointStyle === 'object') {
-                               type = pointStyle.toString();
-                               if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
-                                       ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2);
-                                       return;
-                               }
-                       }
-
-                       if (isNaN(radius) || radius <= 0) {
-                               return;
-                       }
-
                        ctx.strokeStyle = vm.borderColor || defaultColor;
                        ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth);
                        ctx.fillStyle = vm.backgroundColor || defaultColor;
 
-                       switch (pointStyle) {
-                       // Default includes circle
-                       default:
-                               ctx.beginPath();
-                               ctx.arc(x, y, radius, 0, Math.PI * 2);
-                               ctx.closePath();
-                               ctx.fill();
-                               break;
-                       case 'triangle':
-                               ctx.beginPath();
-                               edgeLength = 3 * radius / Math.sqrt(3);
-                               height = edgeLength * Math.sqrt(3) / 2;
-                               ctx.moveTo(x - edgeLength / 2, y + height / 3);
-                               ctx.lineTo(x + edgeLength / 2, y + height / 3);
-                               ctx.lineTo(x, y - 2 * height / 3);
-                               ctx.closePath();
-                               ctx.fill();
-                               break;
-                       case 'rect':
-                               size = 1 / Math.SQRT2 * radius;
-                               ctx.fillRect(x - size, y - size, 2 * size,  2 * size);
-                               ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
-                               break;
-                       case 'rectRot':
-                               size = 1 / Math.SQRT2 * radius;
-                               ctx.beginPath();
-                               ctx.moveTo(x - size, y);
-                               ctx.lineTo(x, y + size);
-                               ctx.lineTo(x + size, y);
-                               ctx.lineTo(x, y - size);
-                               ctx.closePath();
-                               ctx.fill();
-                               break;
-                       case 'cross':
-                               ctx.beginPath();
-                               ctx.moveTo(x, y + radius);
-                               ctx.lineTo(x, y - radius);
-                               ctx.moveTo(x - radius, y);
-                               ctx.lineTo(x + radius, y);
-                               ctx.closePath();
-                               break;
-                       case 'crossRot':
-                               ctx.beginPath();
-                               xOffset = Math.cos(Math.PI / 4) * radius;
-                               yOffset = Math.sin(Math.PI / 4) * radius;
-                               ctx.moveTo(x - xOffset, y - yOffset);
-                               ctx.lineTo(x + xOffset, y + yOffset);
-                               ctx.moveTo(x - xOffset, y + yOffset);
-                               ctx.lineTo(x + xOffset, y - yOffset);
-                               ctx.closePath();
-                               break;
-                       case 'star':
-                               ctx.beginPath();
-                               ctx.moveTo(x, y + radius);
-                               ctx.lineTo(x, y - radius);
-                               ctx.moveTo(x - radius, y);
-                               ctx.lineTo(x + radius, y);
-                               xOffset = Math.cos(Math.PI / 4) * radius;
-                               yOffset = Math.sin(Math.PI / 4) * radius;
-                               ctx.moveTo(x - xOffset, y - yOffset);
-                               ctx.lineTo(x + xOffset, y + yOffset);
-                               ctx.moveTo(x - xOffset, y + yOffset);
-                               ctx.lineTo(x + xOffset, y - yOffset);
-                               ctx.closePath();
-                               break;
-                       case 'line':
-                               ctx.beginPath();
-                               ctx.moveTo(x - radius, y);
-                               ctx.lineTo(x + radius, y);
-                               ctx.closePath();
-                               break;
-                       case 'dash':
-                               ctx.beginPath();
-                               ctx.moveTo(x, y);
-                               ctx.lineTo(x + radius, y);
-                               ctx.closePath();
-                               break;
-                       }
-
-                       ctx.stroke();
+                       Chart.canvasHelpers.drawPoint(ctx, pointStyle, radius, x, y);
                }
        });
 };
index fa6e8e76f1dda10343a9f61b719bb208ddd3ea28..2db970f3f0f9658172c64a41f625fe1846425c4c 100644 (file)
@@ -52,6 +52,7 @@ describe('Legend block tests', function() {
                                        label: 'dataset3',
                                        borderWidth: 10,
                                        borderColor: 'green',
+                                       pointStyle: 'crossRot',
                                        data: []
                                }],
                                labels: []
@@ -68,6 +69,7 @@ describe('Legend block tests', function() {
                        lineJoin: undefined,
                        lineWidth: undefined,
                        strokeStyle: undefined,
+                       pointStyle: undefined,
                        datasetIndex: 0
                }, {
                        text: 'dataset2',
@@ -79,6 +81,7 @@ describe('Legend block tests', function() {
                        lineJoin: 'miter',
                        lineWidth: undefined,
                        strokeStyle: undefined,
+                       pointStyle: undefined,
                        datasetIndex: 1
                }, {
                        text: 'dataset3',
@@ -90,6 +93,7 @@ describe('Legend block tests', function() {
                        lineJoin: undefined,
                        lineWidth: 10,
                        strokeStyle: 'green',
+                       pointStyle: 'crossRot',
                        datasetIndex: 2
                }]);
        });
index 674682660caefcf0a4e6eae4b97068f52a59cb2b..c257f7375ca5d7fd05a638ec151f3c6defcacf25 100644 (file)
@@ -164,6 +164,9 @@ describe('Point element tests', function() {
                }, {
                        name: 'setFillStyle',
                        args: ['rgba(0, 255, 0)']
+               }, {
+                       name: 'beginPath',
+                       args: []
                }, {
                        name: 'fillRect',
                        args: [10 - 1 / Math.SQRT2 * 2, 15 - 1 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2, 2 / Math.SQRT2 * 2]