forked from CITKParus/P8-Panels
122 lines
5.3 KiB
JavaScript
122 lines
5.3 KiB
JavaScript
/*
|
||
Парус 8 - Панели мониторинга - Заголовок
|
||
Хуки для заголовка
|
||
*/
|
||
|
||
//---------------------
|
||
//Подключение библиотек
|
||
//---------------------
|
||
|
||
import { useState, useEffect, useCallback, useRef, useMemo } from "react"; //Классы React
|
||
import { P8P_HEADER_MIN_FILTER_WIDTH } from "./p8p_header_constants"; //Константы заголовка
|
||
|
||
//-----------
|
||
//Тело модуля
|
||
//-----------
|
||
|
||
//Кастомный хук для определения информации об отображении
|
||
const useP8PHeaderVisibleInfo = (containerRef, maxDisplay, totalFilters) => {
|
||
//Отображаемое количество
|
||
const [visibleCount, setVisibleCount] = useState(maxDisplay > 0 ? maxDisplay : 0);
|
||
//Признак переполненности
|
||
const [isOverflowed, setIsOverflowed] = useState(false);
|
||
//Признак уменьшения меньше минимального значения
|
||
const [isLessMinWidth, setIsLessMinWidth] = useState(false);
|
||
|
||
//Пересчет количество отображаемых
|
||
const recalcVisibleCount = useCallback(container => {
|
||
//Определяем дочерние элементы
|
||
const items = container.children;
|
||
//Определяем параметры контейнера
|
||
const containerRect = container.getBoundingClientRect();
|
||
//Если блок меньше минимального значения
|
||
if (containerRect.width < P8P_HEADER_MIN_FILTER_WIDTH && items.length > 0) {
|
||
//Информируем, что невозможно показать
|
||
setVisibleCount(0);
|
||
setIsOverflowed(true);
|
||
setIsLessMinWidth(true);
|
||
return;
|
||
}
|
||
//Обнуляем счетчик видимых
|
||
let visible = 0;
|
||
//Обходим дочерние элменты
|
||
for (let i = 0; i < items.length; i++) {
|
||
//Определяем параметры элемента
|
||
const itemRect = items[i].getBoundingClientRect();
|
||
//Проверяем, полностью ли элемент виден в контейнере
|
||
if (itemRect.bottom <= containerRect.bottom) {
|
||
visible++;
|
||
} else {
|
||
//Если один элемент скрыт, то и все последующие скрыты (при row-direction)
|
||
break;
|
||
}
|
||
}
|
||
//Устанавливаем отображаемых
|
||
setVisibleCount(visible);
|
||
setIsOverflowed(visible < items.length);
|
||
setIsLessMinWidth(false);
|
||
}, []);
|
||
|
||
//При открытии страницы
|
||
useEffect(() => {
|
||
//Определяем контейнер
|
||
const container = containerRef.current;
|
||
//Если контейнер не определен или установлено максимально отображение - не отслеживаем
|
||
if (!container || maxDisplay > 0) {
|
||
setIsOverflowed(maxDisplay < totalFilters);
|
||
return;
|
||
}
|
||
//Пересчет количество отображаемых
|
||
recalcVisibleCount(container);
|
||
//Определяем отслеживание
|
||
const observer = new ResizeObserver(() => {
|
||
//Пересчет количество отображаемых
|
||
recalcVisibleCount(container);
|
||
});
|
||
//Подключаем отслеживание
|
||
observer.observe(container);
|
||
//При закрытии компонента
|
||
return () => observer.disconnect();
|
||
}, [containerRef, maxDisplay, recalcVisibleCount, totalFilters]);
|
||
//Возвращаем данные
|
||
return { visibleCount, isOverflowed, isLessMinWidth };
|
||
};
|
||
|
||
//Хук состояния фильтра
|
||
const useP8PHeaderFilter = ({ filters, maxDisplay }) => {
|
||
//Собственное состояние - контейнер элементов
|
||
const gridRef = useRef(null);
|
||
|
||
//Собственное состояние - элемент выпадающего списка
|
||
const [anchorEl, setAnchorEl] = useState(null);
|
||
//Собственное состояние - информация об отображении
|
||
const { visibleCount, isOverflowed, isLessMinWidth } = useP8PHeaderVisibleInfo(gridRef, maxDisplay, filters.length);
|
||
|
||
//Отображаемые фильтры
|
||
const allowedFilters = useMemo(() => {
|
||
if (Array.isArray(filters) && filters.length > 0) {
|
||
return filters.slice(0, maxDisplay || filters.length);
|
||
} else {
|
||
return [];
|
||
}
|
||
}, [filters, maxDisplay]);
|
||
|
||
//По нажатию на меню скрытых элементов
|
||
const handleFilterMoreOpen = event => {
|
||
setAnchorEl(event.currentTarget);
|
||
};
|
||
|
||
//При закрытии меню скрытых элементов
|
||
const handleFilterMoreClose = () => {
|
||
setAnchorEl(null);
|
||
};
|
||
|
||
return { gridRef, anchorEl, allowedFilters, visibleCount, isOverflowed, isLessMinWidth, handleFilterMoreOpen, handleFilterMoreClose };
|
||
};
|
||
|
||
//----------------
|
||
//Интерфейс модуля
|
||
//----------------
|
||
|
||
export { useP8PHeaderFilter };
|