diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
index c1ded0f6d..89327b065 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
@@ -41,8 +41,16 @@
-
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss
index 484355967..ab80f3d01 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss
@@ -62,9 +62,10 @@ my-edit-button {
min-width: 190px;
}
-::ng-deep .chartjs-render-monitor {
- position: relative;
- top: 1px;
+.chart-container {
+ // Sync these values with the template
+ width: 40vw;
+ height: 100px;
}
.video-channels-header {
diff --git a/client/src/app/shared/shared-main/angular/defer-loading.directive.ts b/client/src/app/shared/shared-main/angular/defer-loading.directive.ts
new file mode 100644
index 000000000..9a10e90e3
--- /dev/null
+++ b/client/src/app/shared/shared-main/angular/defer-loading.directive.ts
@@ -0,0 +1,76 @@
+import * as debug from 'debug'
+import {
+ AfterViewInit,
+ ChangeDetectorRef,
+ ContentChild,
+ Directive,
+ ElementRef,
+ EmbeddedViewRef,
+ EventEmitter,
+ OnDestroy,
+ Output,
+ TemplateRef,
+ ViewContainerRef
+} from '@angular/core'
+
+const logger = debug('peertube:main:DeferLoadingDirective')
+
+@Directive({
+ selector: '[myDeferLoading]'
+})
+export class DeferLoadingDirective implements AfterViewInit, OnDestroy {
+ @ContentChild(TemplateRef) template: TemplateRef
+
+ @Output() loaded: EventEmitter = new EventEmitter()
+
+ view: EmbeddedViewRef
+
+ private observer: IntersectionObserver
+
+ constructor (
+ private el: ElementRef,
+ private viewContainer: ViewContainerRef,
+ private cd: ChangeDetectorRef
+ ) { }
+
+ ngAfterViewInit () {
+ if (this.hasIncompatibleBrowser()) {
+ return this.load()
+ }
+
+ this.observer = new IntersectionObserver(entries => {
+ const entry = entries[0]
+ if (!entry.isIntersecting || entry.target !== this.el.nativeElement) return
+
+ this.observer.unobserve(this.el.nativeElement)
+ this.load()
+ }, { threshold: 0.1 })
+
+ this.observer.observe(this.el.nativeElement)
+ }
+
+ load () {
+ if (this.isLoaded()) return
+
+ logger('Loading component')
+
+ this.viewContainer.clear()
+ this.view = this.viewContainer.createEmbeddedView(this.template, {}, 0)
+ this.loaded.emit()
+ this.cd.detectChanges()
+ }
+
+ isLoaded () {
+ return this.view != null
+ }
+
+ ngOnDestroy () {
+ this.view = null
+
+ if (this.observer) this.observer.disconnect()
+ }
+
+ private hasIncompatibleBrowser () {
+ return !('IntersectionObserver' in window)
+ }
+}
diff --git a/client/src/app/shared/shared-main/angular/index.ts b/client/src/app/shared/shared-main/angular/index.ts
index 069b7f654..4b87c2952 100644
--- a/client/src/app/shared/shared-main/angular/index.ts
+++ b/client/src/app/shared/shared-main/angular/index.ts
@@ -1,5 +1,6 @@
export * from './autofocus.directive'
export * from './bytes.pipe'
+export * from './defer-loading.directive'
export * from './duration-formatter.pipe'
export * from './from-now.pipe'
export * from './infinite-scroller.directive'
diff --git a/client/src/app/shared/shared-main/shared-main.module.ts b/client/src/app/shared/shared-main/shared-main.module.ts
index 10fc364b3..d83af9a66 100644
--- a/client/src/app/shared/shared-main/shared-main.module.ts
+++ b/client/src/app/shared/shared-main/shared-main.module.ts
@@ -21,6 +21,7 @@ import { AccountService } from './account'
import {
AutofocusDirective,
BytesPipe,
+ DeferLoadingDirective,
DurationFormatterPipe,
FromNowPipe,
InfiniteScrollerDirective,
@@ -80,6 +81,7 @@ import { VideoChannelService } from './video-channel'
BytesPipe,
DurationFormatterPipe,
AutofocusDirective,
+ DeferLoadingDirective,
InfiniteScrollerDirective,
PeerTubeTemplateDirective,
@@ -139,6 +141,7 @@ import { VideoChannelService } from './video-channel'
NumberFormatterPipe,
DurationFormatterPipe,
AutofocusDirective,
+ DeferLoadingDirective,
InfiniteScrollerDirective,
PeerTubeTemplateDirective,