From: Jukka Kurkela Date: Tue, 6 Oct 2020 11:41:16 +0000 (+0300) Subject: Add maxWidth/maxHeight options for legend (#7852) X-Git-Tag: v3.0.0-beta.4~17 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=06b5325778b0742ccf10bd9a65f8044e4b4df224;p=thirdparty%2FChart.js.git Add maxWidth/maxHeight options for legend (#7852) --- diff --git a/docs/docs/configuration/legend.md b/docs/docs/configuration/legend.md index ff6791d78..02e2d1a23 100644 --- a/docs/docs/configuration/legend.md +++ b/docs/docs/configuration/legend.md @@ -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]`. diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 8856ceef9..e88d9f3f9 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -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; } diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index ddff43a49..9c69b79fa 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -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); } } diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 99f665a10..2a39bd937 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -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(); diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index 810c9d7a3..c9239e0d6 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -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(); diff --git a/src/helpers/helpers.canvas.js b/src/helpers/helpers.canvas.js index 00bfc0fdf..a34925966 100644 --- a/src/helpers/helpers.canvas.js +++ b/src/helpers/helpers.canvas.js @@ -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': diff --git a/src/helpers/helpers.dom.js b/src/helpers/helpers.dom.js index e813079ef..220f0ea46 100644 --- a/src/helpers/helpers.dom.js +++ b/src/helpers/helpers.dom.js @@ -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; diff --git a/src/helpers/helpers.easing.js b/src/helpers/helpers.easing.js index b3ccd4fb1..7860ed03b 100644 --- a/src/helpers/helpers.easing.js +++ b/src/helpers/helpers.easing.js @@ -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; diff --git a/src/helpers/helpers.math.js b/src/helpers/helpers.math.js index d47689352..26e522013 100644 --- a/src/helpers/helpers.math.js +++ b/src/helpers/helpers.math.js @@ -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 diff --git a/src/plugins/plugin.filler.js b/src/plugins/plugin.filler.js index ce903bc47..c27e4d377 100644 --- a/src/plugins/plugin.filler.js +++ b/src/plugins/plugin.filler.js @@ -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 { diff --git a/src/plugins/plugin.legend.js b/src/plugins/plugin.legend.js index ac3902094..9f6f894fe 100644 --- a/src/plugins/plugin.legend.js +++ b/src/plugins/plugin.legend.js @@ -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() {} diff --git a/src/plugins/plugin.title.js b/src/plugins/plugin.title.js index 594615a9b..5350495f9 100644 --- a/src/plugins/plugin.title.js +++ b/src/plugins/plugin.title.js @@ -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(); diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 1fea73ecf..4e2f5b9c1 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -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,