M: Improve graph UI
This commit is contained in:
parent
c97dae223b
commit
2083c11ff5
|
@ -11,7 +11,15 @@ export default [
|
|||
...typescriptPlugin.configs.recommendedTypeChecked,
|
||||
...typescriptPlugin.configs.stylisticTypeChecked,
|
||||
{
|
||||
ignores: ['**/parser.ts', '**/node_modules/**', '**/public/**', 'eslint.config.js']
|
||||
ignores: [
|
||||
'**/parser.ts',
|
||||
'**/node_modules/**',
|
||||
'**/public/**',
|
||||
'**/dist/**',
|
||||
'eslint.config.js',
|
||||
'tailwind.config.js',
|
||||
'postcss.config.js'
|
||||
]
|
||||
},
|
||||
{
|
||||
languageOptions: {
|
||||
|
|
|
@ -119,6 +119,7 @@ export { BiCollapse as IconGraphCollapse } from 'react-icons/bi';
|
|||
export { BiExpand as IconGraphExpand } from 'react-icons/bi';
|
||||
export { LuMaximize as IconGraphMaximize } from 'react-icons/lu';
|
||||
export { BiGitBranch as IconGraphInputs } from 'react-icons/bi';
|
||||
export { TbEarScan as IconGraphInverse } from 'react-icons/tb';
|
||||
export { BiGitMerge as IconGraphOutputs } from 'react-icons/bi';
|
||||
export { LuAtom as IconGraphCore } from 'react-icons/lu';
|
||||
export { LuRotate3D as IconRotate3D } from 'react-icons/lu';
|
||||
|
|
|
@ -82,7 +82,8 @@ function PickMultiConstituenta({ id, schema, prefixID, rows, selected, setSelect
|
|||
{schema ? (
|
||||
<ToolbarGraphSelection
|
||||
graph={schema.graph}
|
||||
core={schema.items.filter(cst => isBasicConcept(cst.cst_type)).map(cst => cst.id)}
|
||||
isCore={cstID => isBasicConcept(schema.cstByID.get(cstID)?.cst_type)}
|
||||
isOwned={cstID => !schema.cstByID.get(cstID)?.is_inherited ?? false}
|
||||
setSelected={setSelected}
|
||||
emptySelection={selected.length === 0}
|
||||
className='w-full ml-8'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { Graph } from '@/models/Graph';
|
||||
|
||||
|
@ -7,8 +8,10 @@ import {
|
|||
IconGraphCore,
|
||||
IconGraphExpand,
|
||||
IconGraphInputs,
|
||||
IconGraphInverse,
|
||||
IconGraphMaximize,
|
||||
IconGraphOutputs,
|
||||
IconPredecessor,
|
||||
IconReset
|
||||
} from '../Icons';
|
||||
import { CProps } from '../props';
|
||||
|
@ -16,7 +19,8 @@ import MiniButton from '../ui/MiniButton';
|
|||
|
||||
interface ToolbarGraphSelectionProps extends CProps.Styling {
|
||||
graph: Graph;
|
||||
core: number[];
|
||||
isCore: (item: number) => boolean;
|
||||
isOwned: (item: number) => boolean;
|
||||
setSelected: React.Dispatch<React.SetStateAction<number[]>>;
|
||||
emptySelection?: boolean;
|
||||
}
|
||||
|
@ -24,11 +28,27 @@ interface ToolbarGraphSelectionProps extends CProps.Styling {
|
|||
function ToolbarGraphSelection({
|
||||
className,
|
||||
graph,
|
||||
core,
|
||||
isCore,
|
||||
isOwned,
|
||||
setSelected,
|
||||
emptySelection,
|
||||
...restProps
|
||||
}: ToolbarGraphSelectionProps) {
|
||||
const handleSelectCore = useCallback(() => {
|
||||
const core = [...graph.nodes.keys()].filter(isCore);
|
||||
setSelected([...core, ...graph.expandInputs(core)]);
|
||||
}, [setSelected, graph, isCore]);
|
||||
|
||||
const handleSelectOwned = useCallback(
|
||||
() => setSelected([...graph.nodes.keys()].filter(isOwned)),
|
||||
[setSelected, graph, isOwned]
|
||||
);
|
||||
|
||||
const handleInvertSelection = useCallback(
|
||||
() => setSelected(prev => [...graph.nodes.keys()].filter(item => !prev.includes(item))),
|
||||
[setSelected, graph]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={clsx('cc-icons', className)} {...restProps}>
|
||||
<MiniButton
|
||||
|
@ -67,10 +87,20 @@ function ToolbarGraphSelection({
|
|||
onClick={() => setSelected(prev => [...prev, ...graph.expandOutputs(prev)])}
|
||||
disabled={emptySelection}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Инвертировать'
|
||||
icon={<IconGraphInverse size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleInvertSelection}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Выделить ядро'
|
||||
icon={<IconGraphCore size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => setSelected([...core, ...graph.expandInputs(core)])}
|
||||
onClick={handleSelectCore}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Выделить собственные'
|
||||
icon={<IconPredecessor size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleSelectOwned}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -202,7 +202,7 @@ export function guessCstType(hint: string, defaultType: CstType = CstType.TERM):
|
|||
/**
|
||||
* Evaluate if {@link CstType} is basic concept.
|
||||
*/
|
||||
export function isBasicConcept(type: CstType): boolean {
|
||||
export function isBasicConcept(type?: CstType): boolean {
|
||||
// prettier-ignore
|
||||
switch (type) {
|
||||
case CstType.BASE: return true;
|
||||
|
@ -213,6 +213,7 @@ export function isBasicConcept(type: CstType): boolean {
|
|||
case CstType.FUNCTION: return false;
|
||||
case CstType.PREDICATE: return false;
|
||||
case CstType.THEOREM: return false;
|
||||
case undefined: return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IconRSForm } from '@/components/Icons';
|
||||
import { IconChild, IconPredecessor, IconRSForm } from '@/components/Icons';
|
||||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
|
@ -17,8 +17,8 @@ function HelpThesaurus() {
|
|||
<h2>Концептуальная схема</h2>
|
||||
<p>
|
||||
<IconRSForm size='1rem' className='inline-icon' />{' '}
|
||||
<LinkTopic text='Концептуальная схема' topic={HelpTopic.CC_SYSTEM} /> (система определений, КС) – совокупность
|
||||
отдельных понятий и утверждений, а также связей между ними, задаваемых определениями.
|
||||
<LinkTopic text='Концептуальная схема' topic={HelpTopic.CC_SYSTEM} /> (<i>система определений, КС</i>) –
|
||||
совокупность отдельных понятий и утверждений, а также связей между ними, задаваемых определениями.
|
||||
</p>
|
||||
<p>
|
||||
Экспликация КС – изложение (процесс и результат) концептуальной схемы с помощью заданного языка описания –
|
||||
|
@ -30,7 +30,82 @@ function HelpThesaurus() {
|
|||
</p>
|
||||
|
||||
<h2>Конституента</h2>
|
||||
<p>Раздел в разработке...</p>
|
||||
<p>
|
||||
Конституента – это выделенная часть КС, являющаяся отдельным понятием, схемой построения понятия, либо
|
||||
утверждением, связывающим введенные понятия.{' '}
|
||||
<LinkTopic text='Аттрибутами конституенты' topic={HelpTopic.CC_CONSTITUENTA} /> в родоструктурной экспликации
|
||||
являются Термин, Конвенция, Типизация (Структура), Формальное определение, Текстовое определение, Комментарий.
|
||||
</p>
|
||||
<ul>
|
||||
По <b>наличию формального определения в рамках КС</b> выделены:
|
||||
<li>
|
||||
базовое понятие (<i>неопределяемое понятие</i>) не имеет определения и задано конвенцией и аксиомами;
|
||||
</li>
|
||||
<li>
|
||||
производное понятие (<i>выводимое понятие</i>) имеет определение.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
<ul>
|
||||
Для описания <b>тесно связанных понятий</b> введены следующие термины:
|
||||
<li>
|
||||
порождающее выражение – формальное определение, основанное на одной внешней конституенте и использующее только
|
||||
формальное разворачивание (не вводит нового предметного содержания);
|
||||
</li>
|
||||
<li>основа данного понятия – понятие, на котором основано порождающее выражение данной конституенты;</li>
|
||||
<li>
|
||||
порожденное понятие данным понятием – понятие, определение которого является порождающим выражением,
|
||||
основанным на данном понятии.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
<ul>
|
||||
Для описания <b>отождествления</b> введены:
|
||||
<li>отождествляемые конституенты – конституенты, состоящие в отождествлении;</li>
|
||||
<li>удаляемая конституента – конституента, удаляемая в ходе отождествления;</li>
|
||||
<li>
|
||||
замещающая конституента – конституента, обозначение которой замещает обозначение удаляемой конституенты в
|
||||
формальных выражениях иных конституент в ходе отождествления;
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
<ul>
|
||||
Для описания <b>наследования</b> конституент в рамках ОСС введены:
|
||||
<li>
|
||||
<IconChild size='1rem' className='inline-icon' /> наследованная конституента – конституента, перенесенная из
|
||||
другой КС в рамках операции синтеза;
|
||||
</li>
|
||||
<li>собственная конституента – конституента, не являющаяся наследником других конституент;</li>
|
||||
<li>
|
||||
<IconPredecessor size='1rem' className='inline-icon' /> исходная конституента для данной конституенты –
|
||||
собственная конституента, прямым или опосредованным наследником которой является данная конституента.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<br />
|
||||
|
||||
<ul>
|
||||
По <b>назначению</b> выделены:
|
||||
<li>
|
||||
базисное множество (X1) задает неопределяемое понятие, представленное структурой множества, чьи элементы
|
||||
различимы и не сравнимы с элементами других базисных множеств;
|
||||
</li>
|
||||
<li>
|
||||
константное множество (C1) задает неопределяемое понятие, моделируемое термом теории множеств, который
|
||||
поддерживает ряд формальных операций над его элементами;
|
||||
</li>
|
||||
<li>
|
||||
родовая структура (S1) задает неопределяемое понятие, имеющее определенную структуру, построенную на базисных
|
||||
множествах и константных множеств. Содержание родовой структуры формируется{' '}
|
||||
<LinkTopic text='отношением типизации' topic={HelpTopic.RSL_TYPES} />, аксиомами и конвенцией;
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Операционная схема синтеза</h2>
|
||||
<p>Раздел в разработке...</p>
|
||||
|
|
|
@ -37,7 +37,7 @@ function ControlsOverlay({ constituenta, disabled, modified, processing, onRenam
|
|||
)}
|
||||
>
|
||||
<span>Имя </span>
|
||||
<span className='ml-1'>{constituenta.alias}</span>
|
||||
<span className='ml-1'>{constituenta?.alias ?? ''}</span>
|
||||
</div>
|
||||
{!disabled || processing ? (
|
||||
<MiniButton
|
||||
|
|
|
@ -324,7 +324,8 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
|
|||
{!focusCst ? (
|
||||
<ToolbarGraphSelection
|
||||
graph={controller.schema!.graph}
|
||||
core={controller.schema!.items.filter(cst => isBasicConcept(cst.cst_type)).map(cst => cst.id)}
|
||||
isCore={cstID => isBasicConcept(controller.schema?.cstByID.get(cstID)?.cst_type)}
|
||||
isOwned={cstID => !controller.schema?.cstByID.get(cstID)?.is_inherited ?? false}
|
||||
setSelected={controller.setSelected}
|
||||
emptySelection={controller.selected.length === 0}
|
||||
/>
|
||||
|
|
|
@ -114,30 +114,28 @@ function TermGraph({
|
|||
const canvasHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
|
||||
|
||||
return (
|
||||
<div className='outline-none'>
|
||||
<div className='relative' style={{ width: canvasWidth, height: canvasHeight }}>
|
||||
<GraphUI
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
ref={graphRef}
|
||||
animated={false}
|
||||
draggable
|
||||
layoutType={layout}
|
||||
selections={selections}
|
||||
onNodeDoubleClick={handleNodeDoubleClick}
|
||||
onNodeClick={handleNodeClick}
|
||||
onNodePointerOver={handleHoverIn}
|
||||
onNodePointerOut={handleHoverOut}
|
||||
minNodeSize={4}
|
||||
maxNodeSize={8}
|
||||
cameraMode={orbit ? 'orbit' : is3D ? 'rotate' : 'pan'}
|
||||
layoutOverrides={
|
||||
layout.includes('tree') ? { nodeLevelRatio: nodes.length < PARAMETER.smallTreeNodes ? 3 : 1 } : undefined
|
||||
}
|
||||
labelFontUrl={resources.graph_font}
|
||||
theme={darkMode ? graphDarkT : graphLightT}
|
||||
/>
|
||||
</div>
|
||||
<div className='relative outline-none' style={{ width: canvasWidth, height: canvasHeight }}>
|
||||
<GraphUI
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
ref={graphRef}
|
||||
animated={false}
|
||||
draggable
|
||||
layoutType={layout}
|
||||
selections={selections}
|
||||
onNodeDoubleClick={handleNodeDoubleClick}
|
||||
onNodeClick={handleNodeClick}
|
||||
onNodePointerOver={handleHoverIn}
|
||||
onNodePointerOut={handleHoverOut}
|
||||
minNodeSize={4}
|
||||
maxNodeSize={8}
|
||||
cameraMode={orbit ? 'orbit' : is3D ? 'rotate' : 'pan'}
|
||||
layoutOverrides={
|
||||
layout.includes('tree') ? { nodeLevelRatio: nodes.length < PARAMETER.smallTreeNodes ? 3 : 1 } : undefined
|
||||
}
|
||||
labelFontUrl={resources.graph_font}
|
||||
theme={darkMode ? graphDarkT : graphLightT}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user