]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Fix legend item layout issue (#5816)
authorAkihiko Kusanagi <nagi@nagi-p.com>
Mon, 12 Nov 2018 07:57:16 +0000 (15:57 +0800)
committerSimon Brunel <simonbrunel@users.noreply.github.com>
Mon, 12 Nov 2018 07:57:16 +0000 (08:57 +0100)
src/plugins/plugin.legend.js
test/specs/plugin.legend.tests.js

index 3f1559c300320cb4c300f0a7d52676508260ae27..8e6b75f65fe01835d5a3ad9e76336ea506c8364b 100644 (file)
@@ -241,7 +241,7 @@ var Legend = Element.extend({
 
                                // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
                                var lineWidths = me.lineWidths = [0];
-                               var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;
+                               var totalHeight = 0;
 
                                ctx.textAlign = 'left';
                                ctx.textBaseline = 'top';
@@ -250,9 +250,9 @@ var Legend = Element.extend({
                                        var boxWidth = getBoxWidth(labelOpts, fontSize);
                                        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;
+                                       if (i === 0 || lineWidths[lineWidths.length - 1] + width + labelOpts.padding > minSize.width) {
+                                               totalHeight += fontSize + labelOpts.padding;
+                                               lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = labelOpts.padding;
                                        }
 
                                        // Store the hitbox width and height here. Final position will be updated in `draw`
@@ -281,7 +281,7 @@ var Legend = Element.extend({
                                        var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
 
                                        // If too tall, go to new column
-                                       if (currentColHeight + itemHeight > minSize.height) {
+                                       if (i > 0 && currentColHeight + itemHeight > minSize.height - vPadding) {
                                                totalWidth += currentColWidth + labelOpts.padding;
                                                columnWidths.push(currentColWidth); // previous column width
 
@@ -412,7 +412,7 @@ var Legend = Element.extend({
                        var isHorizontal = me.isHorizontal();
                        if (isHorizontal) {
                                cursor = {
-                                       x: me.left + ((legendWidth - lineWidths[0]) / 2),
+                                       x: me.left + ((legendWidth - lineWidths[0]) / 2) + labelOpts.padding,
                                        y: me.top + labelOpts.padding,
                                        line: 0
                                };
@@ -431,13 +431,16 @@ var Legend = Element.extend({
                                var x = cursor.x;
                                var y = cursor.y;
 
+                               // Use (me.left + me.minSize.width) and (me.top + me.minSize.height)
+                               // instead of me.right and me.bottom because me.width and me.height
+                               // may have been changed since me.minSize was calculated
                                if (isHorizontal) {
-                                       if (x + width >= legendWidth) {
+                                       if (i > 0 && x + width + labelOpts.padding > me.left + me.minSize.width) {
                                                y = cursor.y += itemHeight;
                                                cursor.line++;
-                                               x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
+                                               x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2) + labelOpts.padding;
                                        }
-                               } else if (y + itemHeight > me.bottom) {
+                               } else if (i > 0 && y + itemHeight > me.top + me.minSize.height) {
                                        x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
                                        y = cursor.y = me.top + labelOpts.padding;
                                        cursor.line++;
@@ -452,7 +455,7 @@ var Legend = Element.extend({
                                fillText(x, y, legendItem, textWidth);
 
                                if (isHorizontal) {
-                                       cursor.x += width + (labelOpts.padding);
+                                       cursor.x += width + labelOpts.padding;
                                } else {
                                        cursor.y += itemHeight;
                                }
index 5b75069aaea6f4db0294b6a893336ceb074291ea..924276587f0ffb8da96f8985d414e12bb5bdd10e 100644 (file)
@@ -176,7 +176,7 @@ describe('Legend block tests', function() {
                expect(makeChart).not.toThrow();
        });
 
-       it('should draw correctly', function() {
+       it('should draw correctly when the legend is positioned on the top', function() {
                var chart = window.acquireChart({
                        type: 'bar',
                        data: {
@@ -205,9 +205,9 @@ describe('Legend block tests', function() {
                expect(chart.legend.legendHitBoxes.length).toBe(3);
 
                [
-                       {h: 12, l: 101, t: 10, w: 93},
-                       {h: 12, l: 205, t: 10, w: 93},
-                       {h: 12, l: 308, t: 10, w: 93}
+                       {h: 12, l: 107, t: 10, w: 93},
+                       {h: 12, l: 210, t: 10, w: 93},
+                       {h: 12, l: 312, t: 10, w: 93}
                ].forEach(function(expected, i) {
                        expect(chart.legend.legendHitBoxes[i].height).toBeCloseToPixel(expected.h);
                        expect(chart.legend.legendHitBoxes[i].left).toBeCloseToPixel(expected.l);
@@ -389,6 +389,142 @@ describe('Legend block tests', function() {
                }]);*/
        });
 
+       it('should draw correctly when the legend is positioned on the left', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [{
+                                       label: 'dataset1',
+                                       backgroundColor: '#f31',
+                                       borderCapStyle: 'butt',
+                                       borderDash: [2, 2],
+                                       borderDashOffset: 5.5,
+                                       data: []
+                               }, {
+                                       label: 'dataset2',
+                                       hidden: true,
+                                       borderJoinStyle: 'miter',
+                                       data: []
+                               }, {
+                                       label: 'dataset3',
+                                       borderWidth: 10,
+                                       borderColor: 'green',
+                                       data: []
+                               }],
+                               labels: []
+                       },
+                       options: {
+                               legend: {
+                                       position: 'left'
+                               }
+                       }
+               });
+
+               expect(chart.legend.legendHitBoxes.length).toBe(3);
+
+               [
+                       {h: 12, l: 10, t: 16, w: 93},
+                       {h: 12, l: 10, t: 38, w: 93},
+                       {h: 12, l: 10, t: 60, w: 93}
+               ].forEach(function(expected, i) {
+                       expect(chart.legend.legendHitBoxes[i].height).toBeCloseToPixel(expected.h);
+                       expect(chart.legend.legendHitBoxes[i].left).toBeCloseToPixel(expected.l);
+                       expect(chart.legend.legendHitBoxes[i].top).toBeCloseToPixel(expected.t);
+                       expect(chart.legend.legendHitBoxes[i].width).toBeCloseToPixel(expected.w);
+               });
+       });
+
+       it('should draw correctly when the legend is positioned on the top and has multiple rows', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [1, 2, 3, 4, 5].map(function(n) {
+                                       return {
+                                               label: 'dataset' + n,
+                                               data: []
+                                       };
+                               }),
+                               labels: []
+                       }
+               });
+
+               expect(chart.legend.left).toBeCloseToPixel(0);
+               expect(chart.legend.top).toBeCloseToPixel(0);
+               expect(chart.legend.width).toBeCloseToPixel(512);
+               expect(chart.legend.height).toBeCloseToPixel(54);
+               expect(chart.legend.legendHitBoxes.length).toBe(5);
+               expect(chart.legend.legendHitBoxes.length).toBe(5);
+
+               [
+                       {h: 12, l: 56, t: 10, w: 93},
+                       {h: 12, l: 158, t: 10, w: 93},
+                       {h: 12, l: 261, t: 10, w: 93},
+                       {h: 12, l: 364, t: 10, w: 93},
+                       {h: 12, l: 210, t: 32, w: 93}
+               ].forEach(function(expected, i) {
+                       expect(chart.legend.legendHitBoxes[i].height).toBeCloseToPixel(expected.h);
+                       expect(chart.legend.legendHitBoxes[i].left).toBeCloseToPixel(expected.l);
+                       expect(chart.legend.legendHitBoxes[i].top).toBeCloseToPixel(expected.t);
+                       expect(chart.legend.legendHitBoxes[i].width).toBeCloseToPixel(expected.w);
+               });
+       });
+
+       it('should draw correctly when the legend is positioned on the left and has multiple columns', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22].map(function(n) {
+                                       return {
+                                               label: 'dataset' + n,
+                                               data: []
+                                       };
+                               }),
+                               labels: []
+                       },
+                       options: {
+                               legend: {
+                                       position: 'left'
+                               }
+                       }
+               });
+
+               expect(chart.legend.left).toBeCloseToPixel(0);
+               expect(chart.legend.top).toBeCloseToPixel(6);
+               expect(chart.legend.width).toBeCloseToPixel(228.7);
+               expect(chart.legend.height).toBeCloseToPixel(478);
+               expect(chart.legend.legendHitBoxes.length).toBe(22);
+
+               [
+                       {h: 12, l: 10, t: 16, w: 93},
+                       {h: 12, l: 10, t: 38, w: 93},
+                       {h: 12, l: 10, t: 60, w: 93},
+                       {h: 12, l: 10, t: 82, w: 93},
+                       {h: 12, l: 10, t: 104, w: 93},
+                       {h: 12, l: 10, t: 126, w: 93},
+                       {h: 12, l: 10, t: 148, w: 93},
+                       {h: 12, l: 10, t: 170, w: 93},
+                       {h: 12, l: 10, t: 192, w: 93},
+                       {h: 12, l: 10, t: 214, w: 99},
+                       {h: 12, l: 10, t: 236, w: 99},
+                       {h: 12, l: 10, t: 258, w: 99},
+                       {h: 12, l: 10, t: 280, w: 99},
+                       {h: 12, l: 10, t: 302, w: 99},
+                       {h: 12, l: 10, t: 324, w: 99},
+                       {h: 12, l: 10, t: 346, w: 99},
+                       {h: 12, l: 10, t: 368, w: 99},
+                       {h: 12, l: 10, t: 390, w: 99},
+                       {h: 12, l: 10, t: 412, w: 99},
+                       {h: 12, l: 10, t: 434, w: 99},
+                       {h: 12, l: 10, t: 456, w: 99},
+                       {h: 12, l: 119, t: 16, w: 99}
+               ].forEach(function(expected, i) {
+                       expect(chart.legend.legendHitBoxes[i].height).toBeCloseToPixel(expected.h);
+                       expect(chart.legend.legendHitBoxes[i].left).toBeCloseToPixel(expected.l);
+                       expect(chart.legend.legendHitBoxes[i].top).toBeCloseToPixel(expected.t);
+                       expect(chart.legend.legendHitBoxes[i].width).toBeCloseToPixel(expected.w);
+               });
+       });
+
        describe('config update', function() {
                it ('should update the options', function() {
                        var chart = acquireChart({