Improve GraphUI. Add sizing parameter

This commit is contained in:
IRBorisov 2024-04-07 19:22:19 +03:00
parent 26fe49b352
commit f041bd172e
16 changed files with 224 additions and 121 deletions

View File

@ -22,6 +22,9 @@ export { LuGlasses as IconReader } from 'react-icons/lu';
export { FiBell as IconFollow } from 'react-icons/fi';
export { FiBellOff as IconFollowOff } from 'react-icons/fi';
export { LuChevronDown as IconDropArrow } from 'react-icons/lu';
export { LuChevronUp as IconDropArrowUp } from 'react-icons/lu';
export { TbColumns as IconList } from 'react-icons/tb';
export { TbColumnsOff as IconListOff } from 'react-icons/tb';
export { BiFontFamily as IconText } from 'react-icons/bi';

View File

@ -3,6 +3,7 @@
import { GraphCanvas as GraphUI } from 'reagraph';
export { type GraphEdge, type GraphNode, type GraphCanvasRef, type LayoutTypes, Sphere, useSelection } from 'reagraph';
export { type GraphEdge, type GraphNode, type GraphCanvasRef, Sphere, useSelection } from 'reagraph';
export { type LayoutTypes as GraphLayout } from 'reagraph';
export default GraphUI;

View File

@ -9,10 +9,12 @@ import { selectDarkT, selectLightT } from '@/styling/color';
interface SelectSingleProps<Option, Group extends GroupBase<Option> = GroupBase<Option>>
extends Omit<Props<Option, false, Group>, 'theme' | 'menuPortalTarget'> {
noPortal?: boolean;
noBorder?: boolean;
}
function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option>>({
noPortal,
noBorder,
...restProps
}: SelectSingleProps<Option, Group>) {
const { darkMode, colors } = useConceptOptions();
@ -20,32 +22,33 @@ function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option
const adjustedStyles: StylesConfig<Option, false, Group> = useMemo(
() => ({
control: (styles, { isDisabled }) => ({
...styles,
control: (defaultStyles, { isDisabled }) => ({
...defaultStyles,
borderRadius: '0.25rem',
...(noBorder ? { borderWidth: 0 } : {}),
cursor: isDisabled ? 'not-allowed' : 'pointer',
boxShadow: 'none'
}),
menuPortal: styles => ({
...styles,
menuPortal: defaultStyles => ({
...defaultStyles,
zIndex: 9999
}),
menuList: styles => ({
...styles,
menuList: defaultStyles => ({
...defaultStyles,
padding: '0px'
}),
option: (styles, { isSelected }) => ({
...styles,
backgroundColor: isSelected ? colors.bgSelected : styles.backgroundColor,
color: isSelected ? colors.fgSelected : styles.color,
option: (defaultStyles, { isSelected }) => ({
...defaultStyles,
backgroundColor: isSelected ? colors.bgSelected : defaultStyles.backgroundColor,
color: isSelected ? colors.fgSelected : defaultStyles.color,
borderWidth: '1px',
borderColor: colors.border
}),
input: styles => ({ ...styles }),
placeholder: styles => ({ ...styles }),
singleValue: styles => ({ ...styles })
input: defaultStyles => ({ ...defaultStyles }),
placeholder: defaultStyles => ({ ...defaultStyles }),
singleValue: defaultStyles => ({ ...defaultStyles })
}),
[colors]
[colors, noBorder]
);
return (

View File

@ -85,8 +85,9 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
return (
<>
<div className='flex'>
<div className='flex divide-x border-x border-t rounded-t-md'>
<SelectSingle
noBorder
placeholder='Выберите категорию'
className='flex-grow border-none'
options={categorySelector}
@ -102,6 +103,7 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
isClearable
/>
<SelectSingle
noBorder
placeholder='Источник'
className='w-[12rem]'
options={templateSelector}

View File

@ -27,7 +27,7 @@ function DlgGraphParams({ hideWindow, initial, onConfirm }: DlgGraphParamsProps)
header='Настройки графа термов'
onSubmit={handleSubmit}
submitText='Применить'
className='flex gap-12 px-6 py-2'
className='flex gap-6 px-6 py-2 w-[35rem]'
>
<div className='flex flex-col gap-1'>
<h1 className='mb-2'>Преобразования</h1>

View File

@ -26,7 +26,12 @@ export enum DependencyMode {
/**
* Represents graph node coloring scheme.
*/
export type GraphColoringScheme = 'none' | 'status' | 'type';
export type GraphColoring = 'none' | 'status' | 'type';
/**
* Represents graph node sizing scheme.
*/
export type GraphSizing = 'none' | 'complex' | 'derived';
/**
* Represents font styles.

View File

@ -1,7 +1,7 @@
/**
* Module: API for miscellaneous frontend model types. Future targets for refactoring aimed at extracting modules.
*/
import { DependencyMode, FontStyle, ILibraryFilter, LibraryFilterStrategy } from './miscellaneous';
import { DependencyMode, FontStyle, GraphSizing, ILibraryFilter, LibraryFilterStrategy } from './miscellaneous';
import { IConstituenta, IRSForm } from './rsform';
/**
@ -56,3 +56,16 @@ export function filterFromStrategy(strategy: LibraryFilterStrategy): ILibraryFil
case LibraryFilterStrategy.OWNED: return { is_owned: true };
}
}
/**
* Apply {@link GraphSizing} to a given {@link IConstituenta}.
*/
export function applyNodeSizing(target: IConstituenta, sizing: GraphSizing): number | undefined {
if (sizing === 'none') {
return undefined;
} else if (sizing === 'complex') {
return target.is_simple_expression ? 1 : 2;
} else {
return target.parent ? 1 : 2;
}
}

View File

@ -3,15 +3,16 @@
import clsx from 'clsx';
import { AnimatePresence } from 'framer-motion';
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
import { GraphEdge, GraphNode, LayoutTypes } from 'reagraph';
import InfoConstituenta from '@/components/info/InfoConstituenta';
import SelectedCounter from '@/components/info/SelectedCounter';
import { GraphEdge, GraphLayout, GraphNode } from '@/components/ui/GraphUI';
import Overlay from '@/components/ui/Overlay';
import { useConceptOptions } from '@/context/OptionsContext';
import DlgGraphParams from '@/dialogs/DlgGraphParams';
import useLocalStorage from '@/hooks/useLocalStorage';
import { GraphColoringScheme, GraphFilterParams } from '@/models/miscellaneous';
import { GraphColoring, GraphFilterParams, GraphSizing } from '@/models/miscellaneous';
import { applyNodeSizing } from '@/models/miscellaneousAPI';
import { ConstituentaID, CstType } from '@/models/rsform';
import { colorBgGraphNode } from '@/styling/color';
import { PARAMETER, storage } from '@/utils/constants';
@ -52,11 +53,9 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
const [hidden, setHidden] = useState<ConstituentaID[]>([]);
const [layout, setLayout] = useLocalStorage<LayoutTypes>(storage.rsgraphLayout, 'treeTd2d');
const [coloringScheme, setColoringScheme] = useLocalStorage<GraphColoringScheme>(
storage.rsgraphColoringScheme,
'type'
);
const [layout, setLayout] = useLocalStorage<GraphLayout>(storage.rsgraphLayout, 'treeTd2d');
const [coloring, setColoring] = useLocalStorage<GraphColoring>(storage.rsgraphColoring, 'type');
const [sizing, setSizing] = useLocalStorage<GraphSizing>(storage.rsgraphSizing, 'derived');
const [orbit, setOrbit] = useState(false);
const is3D = useMemo(() => layout.includes('3d'), [layout]);
@ -91,15 +90,15 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
if (cst) {
result.push({
id: String(node.id),
fill: colorBgGraphNode(cst, coloringScheme, colors),
fill: colorBgGraphNode(cst, coloring, colors),
label: cst.alias,
subLabel: !filterParams.noText ? cst.term_resolved : undefined,
size: cst.parent_alias ? 1 : 2
size: applyNodeSizing(cst, sizing)
});
}
});
return result;
}, [controller.schema, coloringScheme, filtered.nodes, filterParams.noText, colors]);
}, [controller.schema, coloring, sizing, filtered.nodes, filterParams.noText, colors]);
const edges: GraphEdge[] = useMemo(() => {
const result: GraphEdge[] = [];
@ -132,7 +131,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
controller.deleteCst();
}
function handleChangeLayout(newLayout: LayoutTypes) {
function handleChangeLayout(newLayout: GraphLayout) {
if (newLayout === layout) {
return;
}
@ -221,7 +220,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
hideZero
totalCount={controller.schema?.stats?.count_all ?? 0}
selectedCount={controller.selected.length}
position='top-[0.3rem] left-0'
position='top-[4.3rem] sm:top-[0.3rem] left-0'
/>
<GraphToolbar
@ -253,19 +252,21 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
</Overlay>
) : null}
<Overlay position='top-9 left-0' className='flex gap-1'>
<div className='cc-column w-[13.5rem]'>
<Overlay position='top-[6.25rem] sm:top-9 left-0' className='flex gap-1'>
<div className='flex flex-col ml-2 w-[13.5rem]'>
<GraphSelectors
coloring={coloringScheme}
coloring={coloring}
layout={layout}
sizing={sizing}
setLayout={handleChangeLayout}
setColoring={setColoringScheme}
setColoring={setColoring}
setSizing={setSizing}
/>
<ViewHidden
items={hidden}
selected={controller.selected}
schema={controller.schema}
coloringScheme={coloringScheme}
coloringScheme={coloring}
toggleSelection={controller.toggleSelect}
onEdit={onOpenEdit}
/>

View File

@ -1,35 +1,46 @@
import { LayoutTypes } from 'reagraph';
import { GraphLayout } from '@/components/ui/GraphUI';
import SelectSingle from '@/components/ui/SelectSingle';
import { GraphColoringScheme } from '@/models/miscellaneous';
import { mapLabelColoring, mapLabelLayout } from '@/utils/labels';
import { SelectorGraphColoring, SelectorGraphLayout } from '@/utils/selectors';
import { GraphColoring, GraphSizing } from '@/models/miscellaneous';
import { mapLabelColoring, mapLabelLayout, mapLabelSizing } from '@/utils/labels';
import { SelectorGraphColoring, SelectorGraphLayout, SelectorGraphSizing } from '@/utils/selectors';
interface GraphSelectorsProps {
coloring: GraphColoringScheme;
layout: LayoutTypes;
coloring: GraphColoring;
layout: GraphLayout;
sizing: GraphSizing;
setLayout: (newValue: LayoutTypes) => void;
setColoring: (newValue: GraphColoringScheme) => void;
setLayout: (newValue: GraphLayout) => void;
setColoring: (newValue: GraphColoring) => void;
setSizing: (newValue: GraphSizing) => void;
}
function GraphSelectors({ coloring, setColoring, layout, setLayout }: GraphSelectorsProps) {
function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setSizing }: GraphSelectorsProps) {
return (
<div className='px-2 text-sm select-none'>
<SelectSingle
placeholder='Выберите цвет'
options={SelectorGraphColoring}
isSearchable={false}
value={coloring ? { value: coloring, label: mapLabelColoring.get(coloring) } : null}
onChange={data => setColoring(data?.value ?? SelectorGraphColoring[0].value)}
/>
<div className='select-none border rounded-t-md rounded-b-none divide-y'>
<SelectSingle
noBorder
placeholder='Способ расположения'
options={SelectorGraphLayout}
isSearchable={false}
value={layout ? { value: layout, label: mapLabelLayout.get(layout) } : null}
onChange={data => setLayout(data?.value ?? SelectorGraphLayout[0].value)}
/>
<SelectSingle
noBorder
placeholder='Цветовая схема'
options={SelectorGraphColoring}
isSearchable={false}
value={coloring ? { value: coloring, label: mapLabelColoring.get(coloring) } : null}
onChange={data => setColoring(data?.value ?? SelectorGraphColoring[0].value)}
/>
<SelectSingle
noBorder
placeholder='Размер узлов'
options={SelectorGraphSizing}
isSearchable={false}
value={layout ? { value: sizing, label: mapLabelSizing.get(sizing) } : null}
onChange={data => setSizing(data?.value ?? SelectorGraphSizing[0].value)}
/>
</div>
);
}

View File

@ -2,7 +2,7 @@
import { useCallback, useLayoutEffect, useMemo, useRef } from 'react';
import GraphUI, { GraphCanvasRef, GraphEdge, GraphNode, LayoutTypes, useSelection } from '@/components/ui/GraphUI';
import GraphUI, { GraphCanvasRef, GraphEdge, GraphLayout, GraphNode, useSelection } from '@/components/ui/GraphUI';
import { useConceptOptions } from '@/context/OptionsContext';
import { ConstituentaID } from '@/models/rsform';
import { graphDarkT, graphLightT } from '@/styling/color';
@ -13,7 +13,7 @@ interface TermGraphProps {
edges: GraphEdge[];
selectedIDs: ConstituentaID[];
layout: LayoutTypes;
layout: GraphLayout;
is3D: boolean;
orbit: boolean;

View File

@ -1,47 +1,84 @@
'use client';
import { useCallback, useMemo } from 'react';
import clsx from 'clsx';
import { motion } from 'framer-motion';
import { useMemo } from 'react';
import { IconDropArrow, IconDropArrowUp } from '@/components/Icons';
import ConstituentaTooltip from '@/components/info/ConstituentaTooltip';
import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay';
import { useConceptOptions } from '@/context/OptionsContext';
import { GraphColoringScheme } from '@/models/miscellaneous';
import useLocalStorage from '@/hooks/useLocalStorage';
import useWindowSize from '@/hooks/useWindowSize';
import { GraphColoring } from '@/models/miscellaneous';
import { ConstituentaID, IRSForm } from '@/models/rsform';
import { animateDropdown, animateHiddenHeader } from '@/styling/animations';
import { colorBgGraphNode } from '@/styling/color';
import { prefixes } from '@/utils/constants';
import { prefixes, storage } from '@/utils/constants';
interface ViewHiddenProps {
items: ConstituentaID[];
selected: ConstituentaID[];
schema?: IRSForm;
coloringScheme: GraphColoringScheme;
coloringScheme: GraphColoring;
toggleSelection: (cstID: ConstituentaID) => void;
onEdit: (cstID: ConstituentaID) => void;
}
function ViewHidden({ items, selected, toggleSelection, schema, coloringScheme, onEdit }: ViewHiddenProps) {
const { colors, noNavigation } = useConceptOptions();
const dismissedHeight = useMemo(() => {
return !noNavigation ? 'calc(100vh - 28rem - 4px)' : 'calc(100vh - 22.2rem - 4px)';
}, [noNavigation]);
const dismissedStyle = useCallback(
(cstID: ConstituentaID) => {
return selected.includes(cstID) ? { outlineWidth: '2px', outlineStyle: 'solid' } : {};
},
[selected]
);
const { colors, calculateHeight } = useConceptOptions();
const windowSize = useWindowSize();
const localSelected = useMemo(() => items.filter(id => selected.includes(id)), [items, selected]);
const [isFolded, setIsFolded] = useLocalStorage(storage.rsgraphFoldHidden, false);
if (!schema || items.length <= 0) {
return null;
}
return (
<div className='flex flex-col text-sm ml-2 border clr-app w-[12.5rem]'>
<p className='mt-2 text-center'>
<b>Скрытые конституенты</b>
</p>
<div className='flex flex-wrap justify-center gap-2 py-2 overflow-y-auto' style={{ maxHeight: dismissedHeight }}>
<div className='flex flex-col'>
<Overlay position='right-[calc(0.5rem+1px)] top-2'>
<MiniButton
noPadding
noHover
title={!isFolded ? 'Свернуть' : 'Развернуть'}
icon={!isFolded ? <IconDropArrowUp size='1.25rem' /> : <IconDropArrow size='1.25rem' />}
onClick={() => setIsFolded(prev => !prev)}
/>
</Overlay>
<div
className={clsx(
'pt-2', //
'border-x',
'clr-input',
'select-none',
{
'pb-2 border-b': isFolded
}
)}
>
<motion.div
className='w-fit'
animate={!isFolded ? 'open' : 'closed'}
variants={animateHiddenHeader}
initial={false}
>{`Скрытые [${localSelected.length} | ${items.length}]`}</motion.div>
</div>
<motion.div
className={clsx(
'flex flex-wrap justify-center gap-2 py-2',
'border-x border-b rounded-b-md',
'clr-input',
'text-sm',
'overflow-y-auto'
)}
style={{ maxHeight: calculateHeight(windowSize.isSmall ? '12.rem + 2px' : '16.4rem + 2px') }}
initial={false}
animate={!isFolded ? 'open' : 'closed'}
variants={animateDropdown}
>
{items.map(cstID => {
const cst = schema.cstByID.get(cstID)!;
const adjustedColoring = coloringScheme === 'none' ? 'status' : coloringScheme;
@ -54,7 +91,7 @@ function ViewHidden({ items, selected, toggleSelection, schema, coloringScheme,
className='min-w-[3rem] rounded-md text-center cursor-pointer select-none'
style={{
backgroundColor: colorBgGraphNode(cst, adjustedColoring, colors),
...dismissedStyle(cstID)
...(localSelected.includes(cstID) ? { outlineWidth: '2px', outlineStyle: 'solid' } : {})
}}
onClick={() => toggleSelection(cstID)}
onDoubleClick={() => onEdit(cstID)}
@ -65,7 +102,7 @@ function ViewHidden({ items, selected, toggleSelection, schema, coloringScheme,
</div>
);
})}
</div>
</motion.div>
</div>
);
}

View File

@ -74,6 +74,27 @@ export const animateSlideLeft: Variants = {
}
};
export const animateHiddenHeader: Variants = {
open: {
translateX: 'calc(6.5rem - 50%)',
marginLeft: 0,
transition: {
type: 'spring',
bounce: 0,
duration: 0.3
}
},
closed: {
translateX: 0,
marginLeft: '0.75rem',
transition: {
type: 'spring',
bounce: 0,
duration: 0.3
}
}
};
export const animateDropdown: Variants = {
open: {
clipPath: 'inset(0% 0% 0% 0%)',

View File

@ -3,7 +3,7 @@
*/
import { GramData, Grammeme, NounGrams, PartOfSpeech, VerbGrams } from '@/models/language';
import { GraphColoringScheme } from '@/models/miscellaneous';
import { GraphColoring } from '@/models/miscellaneous';
import { CstClass, ExpressionStatus, IConstituenta } from '@/models/rsform';
import { ISyntaxTreeNode, TokenID } from '@/models/rslang';
@ -458,7 +458,7 @@ export function colorFgGrammeme(gram: GramData, colors: IColorTheme): string {
/**
* Determines graph color for {@link IConstituenta}.
*/
export function colorBgGraphNode(cst: IConstituenta, coloringScheme: GraphColoringScheme, colors: IColorTheme): string {
export function colorBgGraphNode(cst: IConstituenta, coloringScheme: GraphColoring, colors: IColorTheme): string {
if (coloringScheme === 'type') {
return colorBgCstClass(cst.cst_class, colors);
}

View File

@ -91,7 +91,9 @@ export const storage = {
rsgraphFilter: 'rsgraph.filter_options',
rsgraphLayout: 'rsgraph.layout',
rsgraphColoringScheme: 'rsgraph.coloring_scheme',
rsgraphColoring: 'rsgraph.coloring',
rsgraphSizing: 'rsgraph.sizing',
rsgraphFoldHidden: 'rsgraph.fold_hidden',
cstFilterMatch: 'cst.filter.match',
cstFilterGraph: 'cst.filter.graph'

View File

@ -4,8 +4,17 @@
* Label is a short text used to represent an entity.
* Description is a long description used in tooltips.
*/
import { GraphLayout } from '@/components/ui/GraphUI';
import { GramData, Grammeme, ReferenceType } from '@/models/language';
import { CstMatchMode, DependencyMode, HelpTopic, LibraryFilterStrategy, UserAccessMode } from '@/models/miscellaneous';
import {
CstMatchMode,
DependencyMode,
GraphColoring,
GraphSizing,
HelpTopic,
LibraryFilterStrategy,
UserAccessMode
} from '@/models/miscellaneous';
import { CstClass, CstType, ExpressionStatus, IConstituenta, IRSForm } from '@/models/rsform';
import {
IArgumentInfo,
@ -284,29 +293,35 @@ export function describeLibraryFilter(strategy: LibraryFilterStrategy): string {
/**
* Retrieves label for graph layout mode.
*/
export const mapLabelLayout: Map<string, string> = new Map([
export const mapLabelLayout: Map<GraphLayout, string> = new Map([
['treeTd2d', 'Граф: ДеревоВ 2D'],
['treeTd3d', 'Граф: ДеревоВ 3D'],
['forceatlas2', 'Граф: Атлас 2D'],
['forceDirected2d', 'Граф: Силы 2D'],
['forceDirected3d', 'Граф: Силы 3D'],
['treeTd2d', 'Граф: ДеревоВер 2D'],
['treeTd3d', 'Граф: ДеревоВер 3D'],
['treeLr2d', 'Граф: ДеревоГор 2D'],
['treeLr3d', 'Граф: ДеревоГор 3D'],
['treeLr2d', 'Граф: ДеревоГ 2D'],
['treeLr3d', 'Граф: ДеревоГ 3D'],
['radialOut2d', 'Граф: Радиус 2D'],
['radialOut3d', 'Граф: Радиус 3D'],
['circular2d', 'Граф: Круговая'],
['hierarchicalTd', 'Граф: ИерархияВер'],
['hierarchicalLr', 'Граф: ИерархияГор'],
['nooverlap', 'Граф: Без перекрытия']
['circular2d', 'Граф: Круговая']
]);
/**
* Retrieves label for graph coloring mode.
* Retrieves label for {@link GraphColoring}.
*/
export const mapLabelColoring: Map<string, string> = new Map([
['none', 'Цвет: моно'],
['status', 'Цвет: статус'],
['type', 'Цвет: класс']
export const mapLabelColoring: Map<GraphColoring, string> = new Map([
['none', 'Цвет: Моно'],
['status', 'Цвет: Статус'],
['type', 'Цвет: Класс']
]);
/**
* Retrieves label for {@link GraphSizing}.
*/
export const mapLabelSizing: Map<GraphSizing, string> = new Map([
['none', 'Узлы: Моно'],
['derived', 'Узлы: Порожденные'],
['complex', 'Узлы: Простые']
]);
/**

View File

@ -1,43 +1,32 @@
/**
* Module: Mappings for selector UI elements. Do not confuse with html selectors
*/
import { LayoutTypes } from 'reagraph';
import { GraphLayout } from '@/components/ui/GraphUI';
import { type GramData, Grammeme, ReferenceType } from '@/models/language';
import { grammemeCompare } from '@/models/languageAPI';
import { GraphColoringScheme } from '@/models/miscellaneous';
import { GraphColoring, GraphSizing } from '@/models/miscellaneous';
import { CstType } from '@/models/rsform';
import { labelGrammeme, labelReferenceType } from './labels';
import { labelGrammeme, labelReferenceType, mapLabelColoring, mapLabelLayout, mapLabelSizing } from './labels';
import { labelCstType } from './labels';
/**
* Represents options for GraphLayout selector.
*/
export const SelectorGraphLayout: { value: LayoutTypes; label: string }[] = [
{ value: 'treeTd2d', label: 'Граф: ДеревоВ 2D' },
{ value: 'treeTd3d', label: 'Граф: ДеревоВ 3D' },
{ value: 'forceatlas2', label: 'Граф: Атлас 2D' },
{ value: 'forceDirected2d', label: 'Граф: Силы 2D' },
{ value: 'forceDirected3d', label: 'Граф: Силы 3D' },
{ value: 'treeLr2d', label: 'Граф: ДеревоГ 2D' },
{ value: 'treeLr3d', label: 'Граф: ДеревоГ 3D' },
{ value: 'radialOut2d', label: 'Граф: Радиус 2D' },
{ value: 'radialOut3d', label: 'Граф: Радиус 3D' }
// { value: 'circular2d', label: 'circular2d'},
// { value: 'nooverlap', label: 'nooverlap'},
// { value: 'hierarchicalTd', label: 'hierarchicalTd'},
// { value: 'hierarchicalLr', label: 'hierarchicalLr'}
];
export const SelectorGraphLayout: { value: GraphLayout; label: string }[] = //
[...mapLabelLayout.entries()].map(item => ({ value: item[0], label: item[1] }));
/**
* Represents options for {@link GraphColoring} selector.
*/
export const SelectorGraphColoring: { value: GraphColoring; label: string }[] = //
[...mapLabelColoring.entries()].map(item => ({ value: item[0], label: item[1] }));
/**
* Represents options for {@link GraphColoringScheme} selector.
* Represents options for {@link GraphSizing} selector.
*/
export const SelectorGraphColoring: { value: GraphColoringScheme; label: string }[] = [
{ value: 'none', label: 'Цвет: моно' },
{ value: 'status', label: 'Цвет: статус' },
{ value: 'type', label: 'Цвет: класс' }
];
export const SelectorGraphSizing: { value: GraphSizing; label: string }[] = //
[...mapLabelSizing.entries()].map(item => ({ value: item[0], label: item[1] }));
/**
* Represents options for {@link CstType} selector.