Finally!
Image viewer

Online demo:

React component:

React demo app:

Наконец-то! Просмотр изображений для web, каким он должен был быть с самого начала!

Мной разработан модуль, предоставляющий приложениям современный лайтбокс для web, максимально приближающий просмотр фотоизображений на веб-странице к просмотру в телефоне (и превосходящий его по возможостям)

В основе - простые идеи:

Фотки на сайте должно быть также удобно смотреть, как в мобильном приложении, и даже лучше - как в Фотошопе!

Изображения любого разрешения и размера должны подгружаться по требованию, как видео, автоматически, при увеличении масштаба пользователем, а об "оптимизации изображений" для сайта давно следует забыть.

Finally image viewer - современный модуль для просмотра изображений в web, реализующий эти принципы и предоставляющий совершенно иной уровень удобства для пользователя.

  • Полная поддержка мобильных браузеров, управление жестами.
  • Свободное увеличение до любого масштаба без необходимости удержания картинки пальцами.
  • Плавный скроллинг картинки без эффекта трения и остановок.
  • При увеличении свыше определённого уровня автоматически подгружается высокое разрешение, если соответствующий файл есть на сервере.
  • Естественное листание галереи и выход из нее разнонаправленными свайпами. Поддержка кнопки "назад" на телефоне.
  • Возможность обходиться при просмотре с мобильного одной рукой.

Установка react компонента

npm install github:valery-designer/finally-lightbox-react

Применение

Импортируйте сам компонент и reference из react:

import { useRef } from 'react';
import Lightbox from 'finally-lightbox-react';

В начале компонента вашего приложения объявите ссылку на лайтбокс:

const lightboxReference = useRef({});

В конце темплейта компонента вашего приложения разместите сам лайтбокс:

<Lightbox lightboxReference = { lightboxReference } />

Компонент лайтбокса размещается в единственном экземпляре, данные об изображениях передаются ему в виде массива. Это позволяет сохранять приложение лёгким.

Чтобы открыть лайтбокс, нужно вызвать функцию openInLightbox по ссылке на экземпляр лайтбокса и передать ей событие и массив ссылок на изображения.

Пример для отдельного изображения:

<img
    src='dog01.jpg'
    onClick = {
        (e) => {
            lightboxReference.current.openInLightbox( e,  [
                { src: 'dog01.jpg' }
            ]);
        }
    }
/>

В атрибуте src тэга img указывается изображение, отображаемое на странице, а в компоненте открывается изображение, источник когорого указан в массиве. Они могут не совпадать, что позволяет использовать в качестве превью или ссылки на изображение любой элемент страницы.

Далее, компонент пытается подгружать последовательно файлы из того же источника, в имени которых к исходному имени перед расширением добавлены обозначения стадий (stage): st0, st1 и st2. То есть, если исходное имя файла, передаваемое в массиве - cat.jpg, для работы компонента достаточно положить рядом файлы cat.st0.jpg, cat.st1.jpg и cat.st2.jpg, содержащие то же изображение во всё большем разрешении.

При этом, самый большой файл cat.st2.jpg будет загружаться лишь по необходимости - при увеличении масштаба просмотра свыше определенного значения.

Если файл стадии на сервере отсутствует, ничего страшного на произойдёт - компонент будет просто увеличивать существующее изображение.

При подготовке файлов стадий нужно учесть, что все они должны быть одних пропорций (иметь одно и то же соотношение сторон). Также, лучше не делать hires-файл второй (st2) стадии безумно большим - чудес всё-таки не бывает, и вероятны подтормаживания интерфейса.

Полный пример для отдельного изображения:

import './App.css';
import { useRef } from 'react';
import Lightbox from 'finally-lightbox-react';

function App() {
  const lightboxReference = useRef({});
  return (
    <>
        <div className="App">
            <img
                src='dog01.jpg'
                onClick = {
                    (e) => {
                        lightboxReference.current.openInLightbox( e,  [
                            { src: 'dog01.jpg' }
                        ]);
                    }
                }
            />
            <Lightbox lightboxReference =  {lightboxReference } />
        </div>
    </>
  )
}

export default App

Пример применения совместно с компонентами material design

import './App.css';
import { useRef } from 'react';
import Lightbox from 'finally-lightbox-react';

// Material UI components
import ImageList from '@mui/material/ImageList';
import ImageListItem from '@mui/material/ImageListItem';

function App() {

    // Reference on lightbox component
    const lightboxReference = useRef({});

    // Images data array to be sent to the openInLightbox function 
    const pets = [ 
        { src:'dog01.jpg', title: 'My dog' }, 
        { src:'cat01.jpg', title: 'My cat' }, 
        { src:'dog02.jpg', title: 'Another dog' } 
    ];

    return (
        <>
        <div className="App">

            <ImageList cols={ 3 } variant={ 'quilted' }>
                { pets.map((item) => (
                    <ImageListItem sx={{ aspectRatio: '1 / 1' }} key={item.src}>
                        <img
                            src={item.src}
                            alt={item.title}
                            onClick = { 
                                (e) => { 
                                    lightboxReference.current.openInLightbox(e, pets); 
                                } 
                            }
                        />
                    </ImageListItem>
                )) }
            </ImageList>

            {/* Lightbox component */}
            <Lightbox lightboxReference={lightboxReference} />

        </div>
        </>
    )
}

export default App;

Учтите, что компонент всё ещё в процессе разработки на стадии альфа-версии. Он не поддерживает trackpad на устройствах apple, есть также проблемы в Safari для ios.