Fix retry logic for image urls
parent
db01332c15
commit
c616ffeb6c
@ -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…
Reference in New Issue