Made a lot of changes to the webtoon reader which may be better for the end user based on some light testing with one user. Not ready for prime-time though
This commit is contained in:
parent
d48e59384f
commit
f2befdd7be
3 changed files with 55 additions and 15 deletions
|
@ -31,7 +31,7 @@
|
|||
<img src="{{item.src}}" style="display: block"
|
||||
class="mx-auto {{pageNum === item.page && showDebugOutline() ? 'active': ''}} {{areImagesWiderThanWindow ? 'full-width' : ''}} {{initFinished ? '' : 'full-opacity'}}"
|
||||
*ngIf="item.page >= pageNum - bufferPages && item.page <= pageNum + bufferPages" rel="nofollow" alt="image"
|
||||
(load)="onImageLoad($event)" id="page-{{item.page}}" [attr.page]="item.page" ondragstart="return false;" onselectstart="return false;">
|
||||
(load)="onImageLoad($event)" (touchstart)="onTouchStart($event)" id="page-{{item.page}}" [attr.page]="item.page" ondragstart="return false;" onselectstart="return false;">
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="atBottom" class="spacer bottom" role="alert" (click)="loadNextChapter.emit()">
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
img, .full-width {
|
||||
max-width: 100% !important;
|
||||
height: auto;
|
||||
|
|
|
@ -157,11 +157,15 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
/**
|
||||
* Debug mode. Will show extra information. Use bitwise (|) operators between different modes to enable different output
|
||||
*/
|
||||
debugMode: DEBUG_MODES = DEBUG_MODES.None;
|
||||
debugMode: DEBUG_MODES = DEBUG_MODES.Outline | DEBUG_MODES.Logs;
|
||||
/**
|
||||
* Debug mode. Will filter out any messages in here so they don't hit the log
|
||||
* Debug mode. Will filter out any messages in here, so they don't hit the log
|
||||
*/
|
||||
debugLogFilter: Array<string> = ['[PREFETCH]', '[Intersection]', '[Visibility]', '[Image Load]'];
|
||||
/**
|
||||
* Total Height of all the images
|
||||
*/
|
||||
totalHeight: number = 0;
|
||||
|
||||
get minPageLoaded() {
|
||||
return Math.min(...Object.values(this.imagesLoaded));
|
||||
|
@ -212,6 +216,10 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.totalHeight = this.mangaReaderService.maxHeight();
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.initScrollHandler();
|
||||
|
||||
this.recalculateImageWidth();
|
||||
|
@ -220,7 +228,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.goToPage.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(page => {
|
||||
const isSamePage = this.pageNum === page;
|
||||
if (isSamePage) { return; }
|
||||
this.debugLog('[GoToPage] jump has occured from ' + this.pageNum + ' to ' + page);
|
||||
this.debugLog('[GoToPage] jump has occurred from ' + this.pageNum + ' to ' + page);
|
||||
|
||||
if (this.pageNum < page) {
|
||||
this.scrollingDirection = PAGING_DIRECTION.FORWARD;
|
||||
|
@ -317,15 +325,26 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
handleScrollEndEvent(event?: any) {
|
||||
if (!this.isScrolling) {
|
||||
if (this.isScrolling) { return; }
|
||||
|
||||
return;
|
||||
const closestImages = Array.from(document.querySelectorAll('img[id^="page-"]')) as HTMLImageElement[];
|
||||
const img = this.findClosestVisibleImage(closestImages);
|
||||
|
||||
if (img != null) {
|
||||
this.setPageNum(parseInt(img.getAttribute('page') || this.pageNum + '', 10));
|
||||
}
|
||||
const newPageNum = parseInt(img?.getAttribute('page') || this.pageNum + '', 10);
|
||||
|
||||
// When a scroll end occurs on the last pre-fetched page, the next load event can cause the page number to be set to the end
|
||||
// of the pages, thus jumping the user a ton of pages.
|
||||
console.log('scroll end page delta: ', Math.abs(newPageNum - this.pageNum));
|
||||
if (Math.abs(newPageNum - this.pageNum) <= 10 && newPageNum != this.pageNum) {
|
||||
console.log('Closest page is: ', newPageNum)
|
||||
this.setPageNum(newPageNum);
|
||||
}
|
||||
|
||||
// if (img != null) {
|
||||
// console.log('Closest page is: ', img.getAttribute('page'))
|
||||
// this.setPageNum(parseInt(img.getAttribute('page') || this.pageNum + '', 10));
|
||||
// }
|
||||
}
|
||||
|
||||
getTotalHeight() {
|
||||
|
@ -354,6 +373,8 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
if (this.scrollingDirection === PAGING_DIRECTION.FORWARD) {
|
||||
const totalHeight = this.getTotalHeight();
|
||||
const totalScroll = this.getTotalScroll();
|
||||
const pageDeltaToTriggerBottomLoad = 2;
|
||||
|
||||
|
||||
// If we were at top but have started scrolling down past page 0, remove top spacer
|
||||
if (this.atTop && this.pageNum > 0) {
|
||||
|
@ -361,7 +382,15 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
if (totalScroll === totalHeight && !this.atBottom) {
|
||||
// If we scroll faster than the images can load, we can end up in a situation where we hit the bottom before we should,
|
||||
// We can either check that the page num is within 10 of the total pages
|
||||
// or we could insert a div that equal the space of the image heights combined to ensure the scroll bar
|
||||
// Same situation, but when the next load of pages, we hit this condition. hence I'm adding a check on the page number to ensure
|
||||
if (totalScroll === totalHeight && !this.atBottom && Math.abs(this.pageNum - this.totalPages) <= pageDeltaToTriggerBottomLoad) {
|
||||
this.debugLog('total Scroll: ', totalScroll);
|
||||
this.debugLog('total height: ', totalHeight);
|
||||
this.debugLog('page delta: ', Math.abs(this.pageNum - this.totalPages));
|
||||
this.debugLog('We hit the bottom of the viewport!');
|
||||
this.atBottom = true;
|
||||
this.cdRef.markForCheck();
|
||||
this.setPageNum(this.totalPages);
|
||||
|
@ -471,7 +500,8 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
const rect = image.getBoundingClientRect();
|
||||
|
||||
// Calculate the distance of the current image to the top of the viewport.
|
||||
const distanceToTop = Math.abs(rect.top);
|
||||
const distanceToTop = Math.abs(rect.top) - rect.height / 2;
|
||||
this.debugLog(`Image ${image.getAttribute('page')} is ${distanceToTop}px from top`)
|
||||
|
||||
// Check if the image is visible within the viewport.
|
||||
if (distanceToTop < closestDistanceToTop) {
|
||||
|
@ -502,9 +532,19 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user touches an image, let's set it as the active page. This ensures their touch always sets the active page
|
||||
* @param event
|
||||
*/
|
||||
onTouchStart(event: TouchEvent) {
|
||||
const newPage = parseInt((event.target as HTMLImageElement).getAttribute('page') || this.pageNum + '', 10);
|
||||
this.debugLog('touch start: ', newPage);
|
||||
this.setPageNum(newPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for an image onLoad. At this point the image is already rendered in DOM (may not be visible)
|
||||
* This will be used to scroll to current page for intial load
|
||||
* This will be used to scroll to current page for initial load
|
||||
* @param event
|
||||
*/
|
||||
onImageLoad(event: any) {
|
||||
|
@ -530,6 +570,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.currentPageElem = this.document.querySelector('img#page-' + this.pageNum);
|
||||
// There needs to be a bit of time before we scroll
|
||||
if (this.currentPageElem && !this.isElementVisible(this.currentPageElem)) {
|
||||
this.debugLog('image load, scrolling to page', this.pageNum);
|
||||
this.scrollToCurrentPage();
|
||||
} else {
|
||||
this.initFinished = true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue