]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add maxWidth/maxHeight options for legend (#7852)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Tue, 6 Oct 2020 11:41:16 +0000 (14:41 +0300)
committerGitHub <noreply@github.com>
Tue, 6 Oct 2020 11:41:16 +0000 (07:41 -0400)
13 files changed:
docs/docs/configuration/legend.md
src/controllers/controller.doughnut.js
src/controllers/controller.polarArea.js
src/core/core.scale.js
src/elements/element.arc.js
src/helpers/helpers.canvas.js
src/helpers/helpers.dom.js
src/helpers/helpers.easing.js
src/helpers/helpers.math.js
src/plugins/plugin.filler.js
src/plugins/plugin.legend.js
src/plugins/plugin.title.js
src/scales/scale.radialLinear.js

index ff6791d78a9f0c5486c87fceeabd4a537198a9c3..02e2d1a23673d998369689d0d8dea6ca832565c6 100644 (file)
@@ -13,6 +13,8 @@ The legend configuration is passed into the `options.legend` namespace. The glob
 | `display` | `boolean` | `true` | Is the legend shown?
 | `position` | `string` | `'top'` | Position of the legend. [more...](#position)
 | `align` | `string` | `'center'` | Alignment of the legend. [more...](#align)
+| `maxHeight` `number` | | Maximum height of the legend, in pixels
+| `maxWidth` `number` | | Maximum width of the legend, in pixels
 | `fullWidth` | `boolean` | `true` | Marks that this box should take the full width of the canvas (pushing down other boxes). This is unlikely to need to be changed in day-to-day use.
 | `onClick` | `function` | | A callback that is called when a click event is registered on a label item. Arguments: `[event, legendItem, legend]`.
 | `onHover` | `function` | | A callback that is called when a 'mousemove' event is registered on top of a label item. Arguments: `[event, legendItem, legend]`.
index 8856ceef9b4d69efab679456561fc8f1d647001c..e88d9f3f9487b715bb4db7f42c4c3bef505bb675 100644 (file)
@@ -1,14 +1,11 @@
 import DatasetController from '../core/core.datasetController';
 import {isArray, valueOrDefault} from '../helpers/helpers.core';
-import {toRadians} from '../helpers/helpers.math';
+import {toRadians, PI, TAU, HALF_PI} from '../helpers/helpers.math';
 
 /**
  * @typedef { import("../core/core.controller").default } Chart
  */
 
-const PI = Math.PI;
-const DOUBLE_PI = PI * 2;
-const HALF_PI = PI / 2;
 
 function getRatioAndOffset(rotation, circumference, cutout) {
        let ratioX = 1;
@@ -16,16 +13,16 @@ function getRatioAndOffset(rotation, circumference, cutout) {
        let offsetX = 0;
        let offsetY = 0;
        // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
-       if (circumference < DOUBLE_PI) {
-               let startAngle = rotation % DOUBLE_PI;
-               startAngle += startAngle >= PI ? -DOUBLE_PI : startAngle < -PI ? DOUBLE_PI : 0;
+       if (circumference < TAU) {
+               let startAngle = rotation % TAU;
+               startAngle += startAngle >= PI ? -TAU : startAngle < -PI ? TAU : 0;
                const endAngle = startAngle + circumference;
                const startX = Math.cos(startAngle);
                const startY = Math.sin(startAngle);
                const endX = Math.cos(endAngle);
                const endY = Math.sin(endAngle);
-               const contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI;
-               const contains90 = (startAngle <= HALF_PI && endAngle >= HALF_PI) || endAngle >= DOUBLE_PI + HALF_PI;
+               const contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= TAU;
+               const contains90 = (startAngle <= HALF_PI && endAngle >= HALF_PI) || endAngle >= TAU + HALF_PI;
                const contains180 = startAngle === -PI || endAngle >= PI;
                const contains270 = (startAngle <= -HALF_PI && endAngle >= -HALF_PI) || endAngle >= PI + HALF_PI;
                const minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);
@@ -84,8 +81,8 @@ export default class DoughnutController extends DatasetController {
         * across all visible datasets.
         */
        _getRotationExtents() {
-               let min = DOUBLE_PI;
-               let max = -DOUBLE_PI;
+               let min = TAU;
+               let max = -TAU;
 
                const me = this;
                const opts = me.chart.options;
@@ -150,7 +147,7 @@ export default class DoughnutController extends DatasetController {
                const opts = me.chart.options;
                const meta = me._cachedMeta;
                const circumference = toRadians(valueOrDefault(me._config.circumference, opts.circumference));
-               return reset && opts.animation.animateRotate ? 0 : this.chart.getDataVisibility(i) ? me.calculateCircumference(meta._parsed[i] * circumference / DOUBLE_PI) : 0;
+               return reset && opts.animation.animateRotate ? 0 : this.chart.getDataVisibility(i) ? me.calculateCircumference(meta._parsed[i] * circumference / TAU) : 0;
        }
 
        updateElements(arcs, start, count, mode) {
@@ -216,7 +213,7 @@ export default class DoughnutController extends DatasetController {
        calculateCircumference(value) {
                const total = this._cachedMeta.total;
                if (total > 0 && !isNaN(value)) {
-                       return DOUBLE_PI * (Math.abs(value) / total);
+                       return TAU * (Math.abs(value) / total);
                }
                return 0;
        }
index ddff43a490b1263dacd1598051b13d4bf7d4dc68..9c69b79fafcd983e2812f9813895b75fd8453942 100644 (file)
@@ -1,11 +1,10 @@
 import DatasetController from '../core/core.datasetController';
-import {toRadians} from '../helpers/helpers.math';
-import {resolve} from '../helpers/helpers.options';
+import {resolve, toRadians, PI, TAU} from '../helpers/index';
 
 function getStartAngleRadians(deg) {
        // radialLinear scale draws angleLines using startAngle. 0 is expected to be at top.
        // Here we adjust to standard unit circle used in drawing, where 0 is at right.
-       return toRadians(deg) - 0.5 * Math.PI;
+       return toRadians(deg) - 0.5 * PI;
 }
 
 export default class PolarAreaController extends DatasetController {
@@ -124,7 +123,7 @@ export default class PolarAreaController extends DatasetController {
 
                return resolve([
                        me.chart.options.elements.arc.angle,
-                       (2 * Math.PI) / count
+                       TAU / count
                ], context, index);
        }
 }
index 99f665a10f00e67a33ed9e1a0804dbb5a109f9c6..2a39bd9370b69b949c796fdb406fdfac9fb35094 100644 (file)
@@ -2,7 +2,7 @@ import defaults from './core.defaults';
 import Element from './core.element';
 import {_alignPixel, _measureText} from '../helpers/helpers.canvas';
 import {callback as call, each, isArray, isFinite, isNullOrUndef, isObject, valueOrDefault} from '../helpers/helpers.core';
-import {_factorize, toDegrees, toRadians, _int16Range} from '../helpers/helpers.math';
+import {_factorize, toDegrees, toRadians, _int16Range, HALF_PI} from '../helpers/helpers.math';
 import {toFont, resolve, toPadding} from '../helpers/helpers.options';
 import Ticks from './core.ticks';
 
@@ -1497,7 +1497,7 @@ export default class Scale extends Element {
                                scaleLabelY = me.top + me.height / 2;
                                textAlign = 'center';
                        }
-                       rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
+                       rotation = isLeft ? -HALF_PI : HALF_PI;
                }
 
                ctx.save();
index 810c9d7a3902c72b4df3a940f8082e71ce3735ad..c9239e0d6e3c32229eecc341ce2ecc295567514b 100644 (file)
@@ -1,7 +1,5 @@
 import Element from '../core/core.element';
-import {_angleBetween, getAngleFromPoint} from '../helpers/helpers.math';
-
-const TAU = Math.PI * 2;
+import {_angleBetween, getAngleFromPoint, TAU, HALF_PI} from '../helpers/index';
 
 function clipArc(ctx, element) {
        const {startAngle, endAngle, pixelMargin, x, y, outerRadius, innerRadius} = element;
@@ -15,7 +13,7 @@ function clipArc(ctx, element) {
                angleMargin = pixelMargin / innerRadius;
                ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
        } else {
-               ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2);
+               ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI);
        }
        ctx.closePath();
        ctx.clip();
index 00bfc0fdff03c966dbbacad7d8559fb8f59245b0..a349259667100b59c49861bf4c25fda5302561d9 100644 (file)
@@ -1,16 +1,12 @@
-import {isArray, isNullOrUndef} from './helpers.core';
+import {
+       isArray, isNullOrUndef, PI, TAU, HALF_PI, QUARTER_PI,
+       TWO_THIRDS_PI, RAD_PER_DEG
+} from './index';
 
 /**
  * @typedef { import("../core/core.controller").default } Chart
  */
 
-const PI = Math.PI;
-const RAD_PER_DEG = PI / 180;
-const DOUBLE_PI = PI * 2;
-const HALF_PI = PI / 2;
-const QUARTER_PI = PI / 4;
-const TWO_THIRDS_PI = PI * 2 / 3;
-
 /**
  * @namespace Chart.helpers.canvas
  */
@@ -148,7 +144,7 @@ export function drawPoint(ctx, options, x, y) {
        switch (style) {
        // Default includes circle
        default:
-               ctx.arc(x, y, radius, 0, DOUBLE_PI);
+               ctx.arc(x, y, radius, 0, TAU);
                ctx.closePath();
                break;
        case 'triangle':
index e813079ef106d7917c54381f02389bb264dcc88f..220f0ea4629aa2f24ad30ce18ff7300e15bf8436 100644 (file)
@@ -1,3 +1,5 @@
+import {INFINITY} from './index';
+
 /**
  * @private
  */
@@ -90,8 +92,6 @@ export function getRelativePosition(evt, chart) {
        };
 }
 
-const infinity = Number.POSITIVE_INFINITY;
-
 function getContainerSize(canvas, width, height) {
        let maxWidth, maxHeight;
 
@@ -114,16 +114,16 @@ function getContainerSize(canvas, width, height) {
        return {
                width,
                height,
-               maxWidth: maxWidth || infinity,
-               maxHeight: maxHeight || infinity
+               maxWidth: maxWidth || INFINITY,
+               maxHeight: maxHeight || INFINITY
        };
 }
 
 export function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
        const style = getComputedStyle(canvas);
        const margins = getPositionedStyle(style, 'margin');
-       const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || infinity;
-       const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || infinity;
+       const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
+       const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
        const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
        let {width, height} = containerSize;
 
index b3ccd4fb106ff2e678b2f2eee42971b7b8e8c155..7860ed03be73a26638c3aec013255f7e2af78694 100644 (file)
@@ -1,3 +1,5 @@
+import {PI, TAU, HALF_PI} from './index';
+
 /**
  * Easing functions adapted from Robert Penner's easing equations.
  * @namespace Chart.helpers.easing.effects
@@ -69,15 +71,15 @@ const effects = {
        },
 
        easeInSine(t) {
-               return -Math.cos(t * (Math.PI / 2)) + 1;
+               return -Math.cos(t * HALF_PI) + 1;
        },
 
        easeOutSine(t) {
-               return Math.sin(t * (Math.PI / 2));
+               return Math.sin(t * HALF_PI);
        },
 
        easeInOutSine(t) {
-               return -0.5 * (Math.cos(Math.PI * t) - 1);
+               return -0.5 * (Math.cos(PI * t) - 1);
        },
 
        easeInExpo(t) {
@@ -136,9 +138,9 @@ const effects = {
                        a = 1;
                        s = p / 4;
                } else {
-                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+                       s = p / TAU * Math.asin(1 / a);
                }
-               return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
+               return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
        },
 
        easeOutElastic(t) {
@@ -158,9 +160,9 @@ const effects = {
                        a = 1;
                        s = p / 4;
                } else {
-                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+                       s = p / TAU * Math.asin(1 / a);
                }
-               return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
+               return a * Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
        },
 
        easeInOutElastic(t) {
@@ -180,12 +182,12 @@ const effects = {
                        a = 1;
                        s = p / 4;
                } else {
-                       s = p / (2 * Math.PI) * Math.asin(1 / a);
+                       s = p / TAU * Math.asin(1 / a);
                }
                if (t < 1) {
-                       return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
+                       return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
                }
-               return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
+               return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * TAU / p) * 0.5 + 1;
        },
        easeInBack(t) {
                const s = 1.70158;
index d47689352e785d50c4ec8c7d5b5ef30402d4d5de..26e522013eed8ad3c46f306e161ebd9323fc3c13 100644 (file)
@@ -1,8 +1,13 @@
 import {isFinite as isFiniteNumber} from './helpers.core';
 
-const PI = Math.PI;
-const TAU = 2 * PI;
-const PITAU = TAU + PI;
+export const PI = Math.PI;
+export const TAU = 2 * PI;
+export const PITAU = TAU + PI;
+export const INFINITY = Number.POSITIVE_INFINITY;
+export const RAD_PER_DEG = PI / 180;
+export const HALF_PI = PI / 2;
+export const QUARTER_PI = PI / 4;
+export const TWO_THIRDS_PI = PI * 2 / 3;
 
 /**
  * @alias Chart.helpers.math
index ce903bc472b248a8c7f08d62cdbf8835dd984827..c27e4d377c0920133868542315f0499b36a5c0e2 100644 (file)
@@ -8,7 +8,7 @@ import Line from '../elements/element.line';
 import {_boundSegment, _boundSegments} from '../helpers/helpers.segment';
 import {clipArea, unclipArea} from '../helpers/helpers.canvas';
 import {isArray, isFinite, valueOrDefault} from '../helpers/helpers.core';
-import {_normalizeAngle} from '../helpers/helpers.math';
+import {TAU, _normalizeAngle} from '../helpers/helpers.math';
 
 /**
  * @typedef { import('../core/core.controller').default } Chart
@@ -106,7 +106,7 @@ class simpleArc {
 
        pathSegment(ctx, bounds, opts) {
                const {x, y, radius} = this;
-               bounds = bounds || {start: 0, end: Math.PI * 2};
+               bounds = bounds || {start: 0, end: TAU};
                if (opts.reverse) {
                        ctx.arc(x, y, radius, bounds.end, bounds.start, true);
                } else {
index ac3902094bbaaf7bef4051102412cee3486d214e..9f6f894fe7101cdd55f4bce025ec927832709719 100644 (file)
@@ -2,9 +2,11 @@ import defaults from '../core/core.defaults';
 import Element from '../core/core.element';
 import layouts from '../core/core.layouts';
 import {drawPoint} from '../helpers/helpers.canvas';
-import {callback as call, merge, valueOrDefault, isNullOrUndef} from '../helpers/helpers.core';
-import {toFont, toPadding} from '../helpers/helpers.options';
-import {getRtlAdapter, overrideTextDirection, restoreTextDirection} from '../helpers/helpers.rtl';
+import {
+       callback as call, merge, valueOrDefault, isNullOrUndef, toFont,
+       toPadding, getRtlAdapter, overrideTextDirection, restoreTextDirection,
+       INFINITY
+} from '../helpers/index';
 
 /**
  * @typedef { import("../platform/platform.base").IEvent } IEvent
@@ -279,8 +281,8 @@ export class Legend extends Element {
                        minSize.width += totalWidth;
                }
 
-               me.width = minSize.width;
-               me.height = minSize.height;
+               me.width = Math.min(minSize.width, opts.maxWidth || INFINITY);
+               me.height = Math.min(minSize.height, opts.maxHeight || INFINITY);
        }
 
        afterFit() {}
index 594615a9b3555d239c108ad32f567a83f2f801b8..5350495f9c8eb5eba048329a76250ddbdefa3af7 100644 (file)
@@ -1,8 +1,7 @@
 import defaults from '../core/core.defaults';
 import Element from '../core/core.element';
 import layouts from '../core/core.layouts';
-import {isArray, mergeIf} from '../helpers/helpers.core';
-import {toPadding, toFont} from '../helpers/helpers.options';
+import {PI, isArray, mergeIf, toPadding, toFont} from '../helpers';
 
 export class Title extends Element {
        constructor(config) {
@@ -178,7 +177,7 @@ export class Title extends Element {
                                break;
                        }
                        maxWidth = bottom - top;
-                       rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
+                       rotation = PI * (opts.position === 'left' ? -0.5 : 0.5);
                }
 
                ctx.save();
index 1fea73ecf680e64c7850e1189a3ee8e71d99bd86..4e2f5b9c1e6472a8d738ed66279c08f2227d76cd 100644 (file)
@@ -1,6 +1,6 @@
 import defaults from '../core/core.defaults';
 import {_longestText} from '../helpers/helpers.canvas';
-import {isNumber, toDegrees, toRadians, _normalizeAngle} from '../helpers/helpers.math';
+import {HALF_PI, isNumber, TAU, toDegrees, toRadians, _normalizeAngle} from '../helpers/helpers.math';
 import LinearScaleBase from './scale.linearbase';
 import Ticks from '../core/core.ticks';
 import {valueOrDefault, isArray, isFinite, callback as callCallback, isNullOrUndef} from '../helpers/helpers.core';
@@ -218,7 +218,7 @@ function drawRadiusLine(scale, gridLineOpts, radius, index) {
        ctx.beginPath();
        if (circular) {
                // Draw circular arcs between the points
-               ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
+               ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU);
        } else {
                // Draw straight lines connecting each index
                pointPosition = scale.getPointPosition(0, radius);
@@ -347,7 +347,7 @@ export default class RadialLinearScale extends LinearScaleBase {
 
        getIndexAngle(index) {
                const chart = this.chart;
-               const angleMultiplier = Math.PI * 2 / chart.data.labels.length;
+               const angleMultiplier = TAU / chart.data.labels.length;
                const options = chart.options || {};
                const startAngle = options.startAngle || 0;
 
@@ -381,7 +381,7 @@ export default class RadialLinearScale extends LinearScaleBase {
 
        getPointPosition(index, distanceFromCenter) {
                const me = this;
-               const angle = me.getIndexAngle(index) - (Math.PI / 2);
+               const angle = me.getIndexAngle(index) - HALF_PI;
                return {
                        x: Math.cos(angle) * distanceFromCenter + me.xCenter,
                        y: Math.sin(angle) * distanceFromCenter + me.yCenter,