Fix retry logic for image urls

main
trivernis 4 months ago
parent db01332c15
commit c616ffeb6c
Signed by: Trivernis
GPG Key ID: 7E6D18B61C8D2F4B

@ -1,106 +1,122 @@
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
DoCheck, DoCheck,
ElementRef, ElementRef,
EventEmitter, EventEmitter,
Input, Input,
OnDestroy, OnDestroy,
OnInit, OnInit,
Output, Output,
ViewChild ViewChild,
} from "@angular/core"; } from "@angular/core";
import {SafeResourceUrl} from "@angular/platform-browser"; import { SafeResourceUrl } from "@angular/platform-browser";
@Component({ @Component({
selector: "app-content-aware-image", selector: "app-content-aware-image",
templateUrl: "./content-aware-image.component.html", templateUrl: "./content-aware-image.component.html",
styleUrls: ["./content-aware-image.component.scss"], styleUrls: ["./content-aware-image.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ContentAwareImageComponent implements OnInit, DoCheck, OnDestroy { export class ContentAwareImageComponent implements OnInit, DoCheck, OnDestroy {
@Input() imageSrc!: string | SafeResourceUrl; @Input() imageSrc!: string | SafeResourceUrl;
@Input() maximizeHeight: boolean = true; @Input() maximizeHeight: boolean = true;
@Input() maximizeWidth: boolean = true; @Input() maximizeWidth: boolean = true;
@Input() borderRadius: string | undefined; @Input() borderRadius: string | undefined;
@Input() decoding: "async" | "sync" | "auto" = "auto"; @Input() decoding: "async" | "sync" | "auto" = "auto";
@Input() maxRetry = 3; @Input() maxRetry = 3;
@Input() retryDelay = 200; @Input() retryDelay = 200;
@ViewChild("image") imageElement?: ElementRef<HTMLImageElement>; @ViewChild("image") imageElement?: ElementRef<HTMLImageElement>;
@ViewChild("imageContainer") imageContainer?: ElementRef<HTMLDivElement>; @ViewChild("imageContainer") imageContainer?: ElementRef<HTMLDivElement>;
@Output() appLoadEnd = new EventEmitter<void>(); @Output() appLoadEnd = new EventEmitter<void>();
@Output() appLoadError = new EventEmitter<void>(); @Output() appLoadError = new EventEmitter<void>();
scaleWidth = false; scaleWidth = false;
private previousHeight = 0; private previousHeight = 0;
private previousWidth = 0; private previousWidth = 0;
private retryCount = 0; private retryCount = 0;
private readonly checkInterval?: number; private readonly checkInterval?: number;
constructor(private changeDetector: ChangeDetectorRef) { constructor(private changeDetector: ChangeDetectorRef) {
this.checkInterval = setInterval(() => this.checkSize(), 1000); this.checkInterval = setInterval(() => this.checkSize(), 1000);
} }
public ngOnInit(): void { public ngOnInit(): void {
if (this.imageElement) { if (this.imageElement) {
this.imageElement.nativeElement.decoding = this.decoding; this.imageElement.nativeElement.decoding = this.decoding;
this.changeDetector.detach(); this.changeDetector.detach();
} }
} }
public ngOnDestroy(): void { public ngOnDestroy(): void {
clearInterval(this.checkInterval); clearInterval(this.checkInterval);
} }
public ngDoCheck(): void { public ngDoCheck(): void {
this.checkSize(); this.checkSize();
} }
public checkSize(): void { public checkSize(): void {
if (this.imageElement?.nativeElement && this.imageContainer?.nativeElement) { if (
this.adjustSize(this.imageElement.nativeElement, this.imageContainer.nativeElement); this.imageElement?.nativeElement &&
} this.imageContainer?.nativeElement
} ) {
this.adjustSize(
this.imageElement.nativeElement,
this.imageContainer.nativeElement,
);
}
}
public onImageLoad(image: HTMLImageElement, imageContainer: HTMLDivElement): void { public onImageLoad(
this.adjustSize(image, imageContainer); image: HTMLImageElement,
this.appLoadEnd.emit(); imageContainer: HTMLDivElement,
} ): void {
this.adjustSize(image, imageContainer);
this.appLoadEnd.emit();
}
/** /**
* Fits the image into the container * Fits the image into the container
* @param {HTMLImageElement} image * @param {HTMLImageElement} image
* @param {HTMLDivElement} imageContainer * @param {HTMLDivElement} imageContainer
*/ */
public adjustSize(image: HTMLImageElement, imageContainer: HTMLDivElement): void { public adjustSize(
const containerHeight = Math.abs(imageContainer.clientHeight); image: HTMLImageElement,
const containerWidth = Math.abs(imageContainer.clientWidth); imageContainer: HTMLDivElement,
): void {
const containerHeight = Math.abs(imageContainer.clientHeight);
const containerWidth = Math.abs(imageContainer.clientWidth);
if (this.previousWidth != containerWidth || this.previousHeight != containerHeight) { if (
this.previousHeight = containerHeight; this.previousWidth !== containerWidth ||
this.previousWidth = containerWidth; this.previousHeight !== containerHeight
const imageRelativeHeight = image.naturalHeight / containerHeight; ) {
const imageRelativeWidth = image.naturalWidth / containerWidth; this.previousHeight = containerHeight;
const scaleWidth = imageRelativeWidth > imageRelativeHeight; this.previousWidth = containerWidth;
const imageRelativeHeight = image.naturalHeight / containerHeight;
const imageRelativeWidth = image.naturalWidth / containerWidth;
const scaleWidth = imageRelativeWidth > imageRelativeHeight;
if (scaleWidth != this.scaleWidth) { if (scaleWidth !== this.scaleWidth) {
this.scaleWidth = scaleWidth; this.scaleWidth = scaleWidth;
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
} }
} }
} }
public onImageLoadError(error: ErrorEvent, image: HTMLImageElement): void { public onImageLoadError(error: ErrorEvent, image: HTMLImageElement): void {
const imageSrc = image.src; const imageSrc = image.src;
if (this.retryCount < this.maxRetry) { if (this.retryCount < this.maxRetry) {
this.retryCount++; this.retryCount++;
setTimeout(() => { image.src = "";
image.src = imageSrc; setTimeout(() => {
}, this.retryDelay * this.retryCount); image.src = imageSrc;
} else { }, this.retryDelay * this.retryCount);
this.appLoadError.emit(); } else {
} this.appLoadError.emit();
} }
}
} }

Loading…
Cancel
Save