]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Expose radial scale point label positions (#8588)
authorEvert Timberg <evert.timberg+github@gmail.com>
Sun, 7 Mar 2021 21:58:45 +0000 (16:58 -0500)
committerGitHub <noreply@github.com>
Sun, 7 Mar 2021 21:58:45 +0000 (16:58 -0500)
docs/docs/getting-started/v3-migration.md
src/scales/scale.radialLinear.js
test/specs/scale.radialLinear.tests.js
types/index.esm.d.ts

index 1aa12040f6d69d0daf057ba5dd5f79e50238cdf8..8803957ad06539ef31b77dc4d4ea76610d91762f 100644 (file)
@@ -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
index 61415d7edf6591dd662ce859a71301d8c816dab0..88034634e2f43c250f23d97775531137bf167d26 100644 (file)
@@ -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
         */
index e70fb9494972df90e405a11e30cf0b497fed515b..955a0353a6db83298c587563baabae892ef59129 100644 (file)
@@ -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() {
index 7d59db582c032f0e2d00ff2f79d6b813fbab5efe..f72cd8ae3f96757a8be171165f4293a4b963f71e 100644 (file)
@@ -3089,6 +3089,7 @@ export interface RadialLinearScale<O extends RadialLinearScaleOptions = RadialLi
   getValueForDistanceFromCenter(distance: number): number;
   getPointPosition(index: number, distanceFromCenter: number): { x: number; y: number; angle: number };
   getPointPositionForValue(index: number, value: number): { x: number; y: number; angle: number };
+  getPointLabelPosition(index: number): ChartArea;
   getBasePosition(index: number): { x: number; y: number; angle: number };
 }
 export const RadialLinearScale: ChartComponent & {