index.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import React, { useEffect, useState, useRef } from 'react';
  2. import Icon from '../Icon';
  3. import Drawer from '../Drawer';
  4. import Thumbnail from '../Thumbnail';
  5. import { ScrollStateType } from '../../constants/type';
  6. import { watchScroll, scrollIntoView } from '../../helpers/utility';
  7. import {
  8. Wrapper, Head, Body, IconWrapper,
  9. } from '../../global/sidebarStyled';
  10. import { ThumbnailsWrapper } from './styled';
  11. type Props = {
  12. isActive?: boolean;
  13. close: () => void;
  14. currentPage: number;
  15. totalPage: number;
  16. getPdfImage: (page: number) => Promise<string>;
  17. };
  18. const Thumbnails: React.FunctionComponent<Props> = ({
  19. isActive = false,
  20. close,
  21. currentPage,
  22. totalPage,
  23. getPdfImage,
  24. }: Props) => {
  25. const containerRef = useRef<HTMLDivElement>(null);
  26. const [scrollIndex, setScrollIndex] = useState(currentPage);
  27. const [elements, setElement] = useState<React.ReactNode[]>([]);
  28. const scrollUpdate = (state: ScrollStateType): void => {
  29. const height = 220;
  30. const index = Math.round((state.lastY + height) / height);
  31. setScrollIndex(index);
  32. };
  33. const createThumbnails = (): void => {
  34. const eleContent: React.ReactNode[] = [];
  35. for (let i = 1; i <= totalPage; i += 1) {
  36. const component = (
  37. <Thumbnail
  38. key={`thumbnail_${i}`}
  39. pageNum={i}
  40. getPdfImage={getPdfImage}
  41. renderingState={[1, 2, 3, 4, 5].includes(i) ? 'RENDERING' : 'LOADING'}
  42. />
  43. );
  44. eleContent.push(component);
  45. }
  46. setElement(eleContent);
  47. };
  48. const updateThumbnails = (): void => {
  49. const renderingIndexQueue = [
  50. scrollIndex - 1,
  51. scrollIndex,
  52. scrollIndex + 1,
  53. scrollIndex + 2,
  54. scrollIndex + 3,
  55. ];
  56. let index = scrollIndex - 5;
  57. const end = scrollIndex + 5;
  58. while (scrollIndex) {
  59. if (elements[index]) {
  60. const pageNum = index + 1;
  61. elements[index] = (
  62. <Thumbnail
  63. key={`thumbnail_${pageNum}`}
  64. pageNum={pageNum}
  65. getPdfImage={getPdfImage}
  66. renderingState={renderingIndexQueue.includes(pageNum) ? 'RENDERING' : 'LOADING'}
  67. />
  68. );
  69. }
  70. index += 1;
  71. if (index >= end) break;
  72. }
  73. if (elements.length) {
  74. setElement([...elements]);
  75. }
  76. };
  77. useEffect(() => {
  78. if (containerRef.current) {
  79. watchScroll(containerRef.current, scrollUpdate);
  80. }
  81. }, [containerRef]);
  82. useEffect(() => {
  83. if (isActive && !elements.length) {
  84. createThumbnails();
  85. }
  86. }, [isActive]);
  87. useEffect(() => {
  88. updateThumbnails();
  89. }, [scrollIndex]);
  90. useEffect(() => {
  91. if (isActive && elements.length) {
  92. const ele: HTMLElement = document.getElementById(`thumbnail_${currentPage}`) as HTMLElement;
  93. scrollIntoView(ele);
  94. }
  95. }, [currentPage, isActive]);
  96. return (
  97. <Drawer anchor="right" open={isActive}>
  98. <Wrapper>
  99. <Head>
  100. <IconWrapper>
  101. <Icon glyph="right-back" onClick={close} />
  102. </IconWrapper>
  103. </Head>
  104. <Body ref={containerRef}>
  105. <ThumbnailsWrapper>
  106. {elements}
  107. </ThumbnailsWrapper>
  108. </Body>
  109. </Wrapper>
  110. </Drawer>
  111. );
  112. };
  113. export default Thumbnails;