All files / common/services text-measure.service.ts

100% Statements 25/25
100% Branches 17/17
100% Functions 4/4
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63                                  1x     17x     357x 357x 357x       192x   192x 192x 192x 192x 192x 192x           357x 341x   16x 16x       357x 1x 1x   356x 178x 178x   178x 178x      
/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
import { inject, Injectable, DOCUMENT } from '@angular/core';
 
export interface FontStyleOverride {
  fontStyle?: string;
  fontVariant?: string;
  fontWeight?: string;
  fontSize?: string;
  fontFamily?: string;
}
 
@Injectable({
  providedIn: 'root'
})
export class TextMeasureService {
  private measureCanvas?: CanvasRenderingContext2D;
  private defaultFont?: string;
  private document = inject(DOCUMENT);
  /** Measure text width in pixel. */
  measureText(text: string, fontRef?: HTMLElement | string, overrides?: FontStyleOverride): number {
    this.ensureCanvas();
    this.setFontStyle(fontRef, overrides);
    return Math.ceil(this.measureCanvas!.measureText(text).width);
  }
  /** Get font styles for `font` CSS short-hand property. */
  getFontStyle(element: HTMLElement, overrides?: FontStyleOverride): string {
    const style = getComputedStyle(element);
    // note: can't use destructuring on `style` as it doesn't work on Firefox
    const fontStyle = overrides?.fontStyle ?? style.fontStyle;
    const fontVariant = overrides?.fontVariant ?? style.fontVariant;
    const fontWeight = overrides?.fontWeight ?? style.fontWeight;
    const fontSize = overrides?.fontSize ?? style.fontSize;
    const fontFamily = overrides?.fontFamily ?? style.fontFamily;
    return `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize} ${fontFamily}`
      .replace(/ +/g, ' ')
      .trim();
  }
 
  private ensureCanvas(): void {
    if (this.measureCanvas) {
      return;
    }
    const canvas = this.document.createElement('canvas') as HTMLCanvasElement;
    this.measureCanvas = canvas.getContext('2d') as CanvasRenderingContext2D;
  }
 
  private setFontStyle(fontRef?: HTMLElement | string, overrides?: FontStyleOverride): void {
    if (typeof fontRef === 'string') {
      this.measureCanvas!.font = fontRef;
      return;
    }
    if (fontRef || overrides) {
      this.measureCanvas!.font = this.getFontStyle(fontRef ?? this.document.body, overrides);
      return;
    }
    this.defaultFont ??= this.getFontStyle(this.document.body);
    this.measureCanvas!.font = this.defaultFont;
  }
}