@crpt/relation-tree
v0.0.8
Published
Members relation tree
Downloads
6
Readme
Getting started
###Build Run yarn install to install all dependencies.
Make some changes, run yarn run test to run both tslint and karma tests.
Package the library with yarn run build.
###Set NPM to use the cloned project In your cloned relation-tree project, type yarn link.
This will do a symbolic link from the global node_modules version to point to this folder.
You should see your changes reflected in the application.
Add this raw @import "~relation-tree/bundles/main.css"; to your application css main file.
Dependencies
Required Peer Dependencies
- [reactstrap]
- [bootstrap]
- [react-router-dom]
- [react]
- [react-dom]
Component parameters
// Content passed in via props
export interface IRelationTreeContainerProp<T extends ITreeFilter> {
height: number; // Высота области, которую занимает компонент дерева
nodeSize: {
nodeHeight: number, // Высота узла дерева
nodeWidth: number // Ширина узла дерева
};
translation: any; // Данные для перевода. См описание пиже
locale: string; // Текущий язык
onInnChange?: (inn: String) => void; // Коллбэк, вызывается когда в дереве нажимают кнопку "Дерево владельца" и происходит перестроение дерева
initialFilter: T; // Объект фильтра с начальными настройками. Описание см. ниже
loadDataSettings: {
getFullTreeCallback?: (filter: T) => Promise<TreeNodeBase>; // Опциональный колбэк для режима, когда дерево со всеми данными подгружается сразу
loadTreePagesCallback?: (filter: T, inn: String, depth: number, pagesize: number, startIndex: number) => Promise<TreeNodeBase>; // Колбэк для подгрузки узла дерева вместе с указанным числом детей. См. ниже
getNodesChildrenCountCallback?: (filter: T, inns: String[]) => Promise<Map<String, number>>; // Опциональный колбэк, для подгрузки числа детей у узлов. Вызывается в случае если метод loadTreePagesCallback возвращает узлы без заполненного поля "число детей"
loadNodeInfo?: (filter: T, inn: String, parentInn: String) => Promise<INodeAttributes>; // Колбэк для подгрузки подробной информации об узле. Используется, когда нажимаем на узел и вылезает окошко с информацией
downloadReportCallback?: (filter: T, inn: String, parentInn: String) => Promise<{ url: String }>; // Колбэк для выгрузки отчета. Возвращает ссылку, по которой можно загрузить отчет.
};
customFilterComponent?: (onFilterChange: (filter: T) => void, initFilter: T) => React.ReactNode; // Функция для переопределения компонента фильтра дерева (шапка с выбором дат и типом - покупатель/продавей)
statusComponent?: () => React.ReactNode; // Кастомный элемент межжу фильтрами и деревом, отображающий статусное состояние и возможно другую информацию
showLoading?: { onStartLoading: () => void, onEndLoading: () => void }; // Набор функций для переобпределения стандартного поведения гуи при загрузке данных. Сейчас вылезает всплывающее окошко.
treeNodeCustomization?: {
edgeWidthFunction?: (node: TreeNodeBase, parent: TreeNodeBase) => number; //Кастомная Функция для определения толщины ребер дерева. Сейчас толщина считается относительно видимых узлов родителя текущего уровня
edgeCustomComponent?: (node: TreeNodeBase, parent: TreeNodeBase, isSelected: boolean, parentTop: number, x_size: number, y_size: number) => React.ReactNode; // Функция для переопределения компонента ребра графа
customTreeNodeComponent?: (node: TreeNodeBase, collapsed: boolean) => React.ReactNode; // Функция для переопределения внешнего вида узла дерева
};
onErrorCallback?: (error, info) => void; // Колбэк, который дергается при ошибках компонента
nodeInformationWidth: number; // Ширина информационной панели справа
onClickTreeNodeLabelCallback: (node: TreeNode, treeFilter: ITreeFilter) => void; // колбэк на нажатие по узел дерева
}
Component methods
closeInformationInfo() // вызывать для закрытия информационной панели
changeInn(node: TreeNode) // Вызывать для смены корня дерева
Локализация
translation - объект с набором локализации
{
'ua': {
"members": {
"title": "Учасники",
"showdatafrom": "Показати дані з",
"showdatato": "по",
"buyer": "Покупець",
"seller": "Продавець",
"inn": "ИНН",
"products": "Products",
"cost": "Cost",
"tp_number_in_packs": "Кількість ТП (в пачках), шт.",
"tp_sum_in_packs": "Сума по всій ТП (включаючи ПДВ), руб.",
"goods_count": "Найменувань товарів, шт.",
"marks_count": "Коди маркувань, шт.",
"download": "Завантажити",
"cancel": "Відміна",
"traders": "Учасники обороту",
"member": "Учасник",
"registered": "З нами",
"common_info": "Загальна інформація",
"documents": "Документи",
"relation_tree":"Дерево зв'язків",
"loading":"Загрузка",
"showdataQuarterYear": "Выберите год",
"showdataQuarter": "Выберите квартал",
"next": "Далее",
"prev": "Назад",
"owner_tree":"Дерево владельца"
}
},
'en': {...},
'fr': {...},
'de': {...},
'ru': {...}
}
locale - один из ключей объекта translation. Изменение языка извне можно делать либо изменением этого параметра, либо вызвав
TreeTranslatorContext.setLocale("ru")
При использовании внутри кастомных компонентов дерева значений, которые нужно перевести, можно использовать компонент
<TreeTranslate contentKey="members.inn">Текст который будет отображаться если перевод по ключу не найден</TreeTranslate>
Фильтр
Объект фильтра, передаваемого в параметре initialFilter должен представлять интерфейс
export interface ITreeFilter {
rootNode: { inn: String, name: String }; // Инн участника, от которого мы строим дерево и название участника
pageSize: number; // Размер страницы подгрузки детей, определяющий еще и максимальное число детей, показываемое на странице (само число детей высчитывается в зависимости от размеров области динамически)
}
По умолчанию используется базовый фильтр
export class TreeFilter implements ITreeFilter {
dateFrom: Date;
dateTo: Date;
buyType: BuyType; //Тип контрагента
rootNode: { inn: String, name: String };
pageSize: number;
needQuarter: boolean = false; // Поквартальный фильтр
quarter: Quarter;
}
export enum BuyType {
SELLER = 'SELLER',
BUYER = 'BUYER'
}
export class Quarter {
year: number;
quarter: QuarterNum;
}
export enum QuarterNum {
FIRST = '1',
SECOND = '2',
THIRD = '3',
FORTH = '4'
}
Подсунув свою реализацию ITreeFilter нужно также подменить компонент фильтра
customFilterComponent?: (onFilterChange: (filter: T) => void, initFilter: T) => React.ReactNode;
Кроме того, колбэки для загрузки данных должны уметь работать с этой реализацией ITreeFilter
Загрузка данных
Подгруженные данные живут в рамках текущего значения фильтра. При изменении фильтра, дерево заново подгружается. Данные кешируются. Есть вариант сразу выгрузить все дерево. Есть вариант выгружать дерево постранично,
loadTreePagesCallback?: (filter: T, inn: String, depth: number, pagesize: number, startIndex: number) => Promise<TreeNodeBase>; // Колбэк для подгрузки узла дерева вместе с указанным числом детей. См. ниже
указывая инн узла, глубину вложенности детей(depth), количество детей, подгружаемое в каждом из уровней вложенности(pagesize), смещение у первого уровня детей указанного участника(startIndex)
export class TreeNodeBase{
name: String;
attributes: INodeAttributes;
children: TreeNodeBase[];
childrenCount: number;
}
export interface INodeAttributes{
inn: String;
}
export class NodeAttributes implements INodeAttributes{
inn: String;
state: String;
role: String;
description: String;
tp_count: number;
tp_sum: number;
goods_count: number;
marks_count: number;
}
Методы подгрузки данных должны возвращать объекты типа TreeNodeBase. Если хотим высчитывать число детей узла отдельным запросом, нужно в колбэке у TreeNodeBase не заполнять поле childrenCount (чтобы было null), тогда будет вызываться колбэк getNodesChildrenCountCallback. В поле attributes должна быть реализация интерфейса INodeAttributes. По умолчанию используется реализация NodeAttributes. При изменении полей аттрибутов узла, необходимо не забыть переопределить параметры
memberInfoComponent?: (node: TreeNodeBase, parentInn: String, changeInn: (inn: String) => void) => React.ReactNode; // Функция для переопределения всплывающего окошка с подробной информацией об узле
customTreeNodeComponent?: (node: TreeNodeBase, collapsed: boolean) => React.ReactNode; // Функция для переопределения внешнего вида узла дерева
Кроме того, сейчас поле tp_sum аттрибутов, используется для подсчета толщины ребра, поэтому при удалении этого поля, нужно не забыть переопределить параметр
edgeWidthFunction?: (node: TreeNodeBase, parent: TreeNodeBase) => number; //Кастомная Функция для определения толщины ребер дерева. Сейчас толщина считается относительно видимых узлов родителя текущего уровня
Также есть возможно переопредить компонент отрисовки дерева
edgeCustomComponent?: (node: TreeNodeBase, parent: TreeNodeBase, isSelected: boolean, parentTop: number, x_size: number, y_size: number) => React.ReactNode; // Функция для переопределения компонента ребра графа
Пример использования:
import { BuyType, Quarter, QuarterNum, RelationTreeContainer, TreeFilter } from 'relation-tree';
...
<RelationTreeContainer height={500} nodeSize={{ nodeWidth: 217, nodeHeight: 58 }}
memberInfoSize={{ width: 360, height: 210 }}
translation={treeTranslations}
locale={currentLocale}
loadDataSettings={{
loadTreePagesCallback: membersApi.loadTreePages,
loadNodeInfo: membersApi.getNodeInfo,
getNodesChildrenCountCallback: membersApi.getNodesChildrenCount,
downloadReportCallback: membersApi.downloadReport
}}
initialFilter={initialFilter}
onErrorCallback={this.onErrorCallback}
goToMemberPage={(inn: String) => {
// tslint:disable-next-line
console.info('open page for inn' + inn);
}}
/>
В данном примере membersApi реализует интерфейс:
export interface IApiService {
downloadReport?(filter: ITreeFilter, inn: String, parentInn: String): Promise<{ url: String }>;
getNodeInfo?(filter: ITreeFilter, inn: String): Promise<INodeAttributes>;
getNodesChildrenCount?(filter: ITreeFilter, inns: String[]): Promise<Map<String, number>>;
loadTreePages?(filter: ITreeFilter, inn: String, depth: number, pagesize: number, startIndex: number): Promise<TreeNodeBase>;
}
И
initialFilter = new TreeFilter(BuyType.BUYER, { inn: '14505458023', name: 'kaka' }, 10, true, new Quarter(2018, QuarterNum.FIRST), null, null);
currentLocale = 'ru';