From: Evert Timberg Date: Sun, 7 Mar 2021 21:58:45 +0000 (-0500) Subject: Expose radial scale point label positions (#8588) X-Git-Tag: v3.0.0-beta.14~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=275fdaf3dad77908053e4598a52093f671dc7b9e;p=thirdparty%2FChart.js.git Expose radial scale point label positions (#8588) --- diff --git a/docs/docs/getting-started/v3-migration.md b/docs/docs/getting-started/v3-migration.md index 1aa12040f..8803957ad 100644 --- a/docs/docs/getting-started/v3-migration.md +++ b/docs/docs/getting-started/v3-migration.md @@ -449,6 +449,7 @@ The private APIs listed below were renamed: * `DatasetController.resyncElements` was renamed to `DatasetController._resyncElements` * `LayoutItem.isFullWidth` was renamed to `LayoutItem.isFullSize` * `RadialLinearScale.setReductions` was renamed to `RadialLinearScale._setReductions` +* `RadialLinearScale.pointLabels` was renamed to `RadialLinearScale._pointLabels` * `Scale.handleMargins` was renamed to `Scale._handleMargins` ### Changed diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 61415d7ed..88034634e 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -90,7 +90,7 @@ function fitWithPointLabels(scale) { const furthestAngles = {}; let i, textSize, pointPosition; - scale._pointLabelSizes = []; + const labelSizes = []; const valueCount = scale.chart.data.labels.length; for (i = 0; i < valueCount; i++) { @@ -98,8 +98,8 @@ function fitWithPointLabels(scale) { const opts = scale.options.pointLabels.setContext(scale.getContext(i)); const plFont = toFont(opts.font); scale.ctx.font = plFont.string; - textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i]); - scale._pointLabelSizes[i] = textSize; + textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale._pointLabels[i]); + labelSizes[i] = textSize; // Add quarter circle to make degree 0 mean top of circle const angleRadians = scale.getIndexAngle(i); @@ -129,6 +129,51 @@ function fitWithPointLabels(scale) { } scale._setReductions(scale.drawingArea, furthestLimits, furthestAngles); + + scale._pointLabelItems = []; + + // Now that text size is determined, compute the full positions + const opts = scale.options; + const tickBackdropHeight = getTickBackdropHeight(opts); + const outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max); + + for (i = 0; i < valueCount; i++) { + // Extra pixels out for some label spacing + const extra = (i === 0 ? tickBackdropHeight / 2 : 0); + const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5); + + const angle = toDegrees(scale.getIndexAngle(i)); + const size = labelSizes[i]; + adjustPointPositionForLabelHeight(angle, size, pointLabelPosition); + + const textAlign = getTextAlignForAngle(angle); + let left; + + if (textAlign === 'left') { + left = pointLabelPosition.x; + } else if (textAlign === 'center') { + left = pointLabelPosition.x - (size.w / 2); + } else { + left = pointLabelPosition.x - size.w; + } + + const right = left + size.w; + + scale._pointLabelItems[i] = { + // Text position + x: pointLabelPosition.x, + y: pointLabelPosition.y, + + // Text rendering data + textAlign, + + // Bounding box + left, + top: pointLabelPosition.y, + right, + bottom: pointLabelPosition.y + size.h, + }; + } } function getTextAlignForAngle(angle) { @@ -153,31 +198,24 @@ function drawPointLabels(scale) { const ctx = scale.ctx; const opts = scale.options; const pointLabelOpts = opts.pointLabels; - const tickBackdropHeight = getTickBackdropHeight(opts); - const outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max); ctx.save(); ctx.textBaseline = 'middle'; for (let i = scale.chart.data.labels.length - 1; i >= 0; i--) { - // Extra pixels out for some label spacing - const extra = (i === 0 ? tickBackdropHeight / 2 : 0); - const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5); - const optsAtIndex = pointLabelOpts.setContext(scale.getContext(i)); const plFont = toFont(optsAtIndex.font); - const angle = toDegrees(scale.getIndexAngle(i)); - adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition); + const {x, y, textAlign} = scale._pointLabelItems[i]; renderText( ctx, - scale.pointLabels[i], - pointLabelPosition.x, - pointLabelPosition.y + (plFont.lineHeight / 2), + scale._pointLabels[i], + x, + y + (plFont.lineHeight / 2), plFont, { color: optsAtIndex.color, - textAlign: getTextAlignForAngle(angle), + textAlign: textAlign, } ); } @@ -238,7 +276,8 @@ export default class RadialLinearScale extends LinearScaleBase { /** @type {number} */ this.drawingArea = undefined; /** @type {string[]} */ - this.pointLabels = []; + this._pointLabels = []; + this._pointLabelItems = []; } setDimensions() { @@ -278,7 +317,7 @@ export default class RadialLinearScale extends LinearScaleBase { LinearScaleBase.prototype.generateTickLabels.call(me, ticks); // Point labels - me.pointLabels = me.chart.data.labels.map((value, index) => { + me._pointLabels = me.chart.data.labels.map((value, index) => { const label = callCallback(me.options.pointLabels.callback, [value, index], me); return label || label === 0 ? label : ''; }); @@ -380,6 +419,16 @@ export default class RadialLinearScale extends LinearScaleBase { return this.getPointPositionForValue(index || 0, this.getBaseValue()); } + getPointLabelPosition(index) { + const {left, top, right, bottom} = this._pointLabelItems[index]; + return { + left, + top, + right, + bottom, + }; + } + /** * @protected */ diff --git a/test/specs/scale.radialLinear.tests.js b/test/specs/scale.radialLinear.tests.js index e70fb9494..955a0353a 100644 --- a/test/specs/scale.radialLinear.tests.js +++ b/test/specs/scale.radialLinear.tests.js @@ -324,7 +324,7 @@ describe('Test the radial linear scale', function() { }); expect(getLabels(chart.scales.r)).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8']); - expect(chart.scales.r.pointLabels).toEqual(['label1', 'label2', 'label3', 'label4', 'label5']); + expect(chart.scales.r._pointLabels).toEqual(['label1', 'label2', 'label3', 'label4', 'label5']); }); it('Should build point labels using the user supplied callback', function() { @@ -349,7 +349,7 @@ describe('Test the radial linear scale', function() { } }); - expect(chart.scales.r.pointLabels).toEqual(['0', '1', '2', '3', '4']); + expect(chart.scales.r._pointLabels).toEqual(['0', '1', '2', '3', '4']); }); it('Should build point labels from falsy values', function() { @@ -363,7 +363,7 @@ describe('Test the radial linear scale', function() { } }); - expect(chart.scales.r.pointLabels).toEqual([0, '', '', '', '', '']); + expect(chart.scales.r._pointLabels).toEqual([0, '', '', '', '', '']); }); it('should correctly set the center point', function() { diff --git a/types/index.esm.d.ts b/types/index.esm.d.ts index 7d59db582..f72cd8ae3 100644 --- a/types/index.esm.d.ts +++ b/types/index.esm.d.ts @@ -3089,6 +3089,7 @@ export interface RadialLinearScale