@7kasper/ngx-fittext
Version:
**@7kasper/ngx-fittext** is an Angular library that allow you fit text in a box or a line.
179 lines (169 loc) • 5.51 kB
text/typescript
import {
Component,
AfterViewInit,
OnDestroy,
Input,
ElementRef,
Renderer2,
Output,
EventEmitter,
ChangeDetectionStrategy,
ViewChild,
} from '@angular/core';
import { fromEvent, Observable, Subscription } from 'rxjs';
export class FitTextComponent implements AfterViewInit, OnDestroy {
stepSize: number = 2;
calcOnResize: boolean = false;
minFontSize: number = 10;
maxFontSize: number = 500;
height: string;
width: string;
lineHeight: string = 'normal';
textAlign: string = 'left';
verticalAlign: boolean = false;
showInfo = new EventEmitter<any>();
wrapperDiv: ElementRef;
controllerDiv: ElementRef;
resizeObservable$: Observable<Event>;
resizeSubscription$: Subscription;
constructor(private renderer: Renderer2) {}
ngAfterViewInit(): void {
//resize event
if (this.calcOnResize) {
this.resizeObservable$ = fromEvent(window, 'resize');
this.resizeSubscription$ = this.resizeObservable$.subscribe((evt) => {
this.fitToBox();
});
}
this.fitToBox(20);
}
ngOnDestroy(): void {
// unsubscribe resize event
this.resizeSubscription$.unsubscribe();
}
async fitToBox(delay?: number) {
// refreshing need delay
if (delay) {
await this.delayView(delay);
}
if (this.verticalAlign) {
this.renderer.setStyle(this.controllerDiv.nativeElement, 'top', '50%');
this.renderer.setStyle(
this.controllerDiv.nativeElement,
'transform',
'translateY(-50%)'
);
}
this.renderer.setStyle(
this.wrapperDiv.nativeElement,
'text-align',
this.textAlign
);
const controllerWidth = this.controllerDiv.nativeElement.offsetWidth;
const controllerHeight = this.controllerDiv.nativeElement.offsetHeight;
const scrollWidth = this.controllerDiv.nativeElement.scrollWidth;
const scrollHeight = this.controllerDiv.nativeElement.scrollHeight;
if (controllerHeight < scrollWidth || controllerWidth < scrollHeight ) {
console.log("small")
this.resizeToSmall();
} else {
console.log("big")
this.resizeToBig();
}
}
private resizeToSmall() {
while (
this.wrapperDiv.nativeElement.offsetWidth <
this.controllerDiv.nativeElement.offsetWidth ||
this.wrapperDiv.nativeElement.offsetHeight <
this.controllerDiv.nativeElement.offsetHeight ||
this.controllerDiv.nativeElement.offsetHeight <
this.controllerDiv.nativeElement.scrollHeight ||
this.controllerDiv.nativeElement.offsetWidth <
this.controllerDiv.nativeElement.scrollWidth
) {
const fs = getComputedStyle(
this.controllerDiv.nativeElement
).getPropertyValue('font-size');
const { size, unit } = this.splitFontSize(fs);
let fontSize = size;
if (fontSize <= this.minFontSize) {
break;
}
fontSize -= this.stepSize;
this.renderer.setStyle(
this.controllerDiv.nativeElement,
'font-size',
`${fontSize}${unit}`
);
this.showInfo.emit({
fontSize: `${fontSize}${unit}`,
});
}
}
private resizeToBig() {
while (
this.controllerDiv.nativeElement.offsetWidth <=
this.wrapperDiv.nativeElement.offsetWidth ||
this.controllerDiv.nativeElement.offsetHeight <=
this.wrapperDiv.nativeElement.offsetHeight
) {
const fs = getComputedStyle(
this.controllerDiv.nativeElement
).getPropertyValue('font-size');
const { size, unit } = this.splitFontSize(fs);
let fontSize = size;
if (fontSize >= this.maxFontSize) {
break;
}
fontSize += this.stepSize;
this.renderer.setStyle(
this.controllerDiv.nativeElement,
'font-size',
`${fontSize}${unit}`
);
this.showInfo.emit({
fontSize: `${fontSize}${unit}`,
});
if (
this.controllerDiv.nativeElement.offsetWidth >
this.wrapperDiv.nativeElement.offsetWidth ||
this.controllerDiv.nativeElement.offsetHeight >
this.wrapperDiv.nativeElement.offsetHeight ||
this.controllerDiv.nativeElement.scrollHeight >
this.controllerDiv.nativeElement.offsetHeight ||
this.controllerDiv.nativeElement.scrollWidth >
this.controllerDiv.nativeElement.offsetWidth
) {
fontSize -= this.stepSize;
this.renderer.setStyle(
this.controllerDiv.nativeElement,
'font-size',
`${fontSize}${unit}`
);
this.showInfo.emit({
fontSize: `${fontSize}${unit}`,
});
break;
}
}
}
private splitFontSize(fs: string) {
const size = fs.match(/\d+/g);
const unit = fs.match(/[a-zA-Z]+/g);
return {
size: size ? Number(size[0]) : 2,
unit: unit ? unit[0] : 'px',
};
}
private async delayView(delayMs: number) {
return new Promise((resolve) => setTimeout(resolve, delayMs));
}
}