Add connection stype support

This commit is contained in:
Paulo Veiga 2022-12-22 04:18:10 +00:00
parent c8482e1764
commit fcfdc5b435
41 changed files with 290 additions and 157 deletions

View File

@ -1,6 +1,9 @@
context('Node manager', () => {
before(() => {
cy.visit('/editor.html');
// Wait for load complate ...
cy.get('[aria-label="vortex-loading"]').should('not.exist');
});
it('shortcut add sibling node', () => {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -7,20 +7,23 @@ import {
fontSizes,
getNextValue,
} from '../../../components/toolbar/ToolbarValueModelBuilder';
import { LineType } from '@wisemapping/mindplot/src/components/ConnectionLine';
import { TopicShapeType } from '@wisemapping/mindplot/src/components/model/INodeModel';
class NodePropertyBuilder {
designer: Designer;
fontSizeModel: NodeProperty<number>;
selectedTopicColorModel: NodeProperty<string>;
fontFamilyModel: NodeProperty<string>;
fontStyleModel: NodeProperty<string>;
borderColorModel: NodeProperty<string>;
fontColorModel: NodeProperty<string>;
topicShapeModel: NodeProperty<string>;
topicIconModel: NodeProperty<string>;
noteModel: NodeProperty<string>;
linkModel: NodeProperty<string>;
private fontSizeModel: NodeProperty<number>;
private selectedTopicColorModel: NodeProperty<string>;
private fontFamilyModel: NodeProperty<string>;
private fontStyleModel: NodeProperty<string>;
private borderColorModel: NodeProperty<string>;
private fontColorModel: NodeProperty<string>;
private topicShapeModel: NodeProperty<TopicShapeType>;
private topicIconModel: NodeProperty<string>;
private connetionStyleModel: NodeProperty<LineType>;
private noteModel: NodeProperty<string>;
private linkModel: NodeProperty<string>;
constructor(designer: Designer) {
this.designer = designer;
@ -34,7 +37,9 @@ class NodePropertyBuilder {
return this.designer.getModel().selectedTopic()?.getFontSize();
}
private uniqueOrNull(propertyGetter: (Topic: Topic) => string | number | null) {
private uniqueOrNull(
propertyGetter: (Topic: Topic) => string | number | null | LineType,
): string {
const nodes = this.designer.getModel().filterSelectedTopics();
return getTheUniqueValueOrNull(nodes, propertyGetter);
}
@ -190,15 +195,20 @@ class NodePropertyBuilder {
return this.fontStyleModel;
}
/**
*
* @returns model to get and set topic shape
*/
getTopicShapeModel(): NodeProperty<string> {
getConnectionStyleModel(): NodeProperty<LineType> {
if (!this.connetionStyleModel)
this.connetionStyleModel = {
getValue: () => this.selectedTopic()?.getConnectionStyle(),
setValue: (value: LineType) => this.designer.changeConnectionStyle(value),
};
return this.connetionStyleModel;
}
getTopicShapeModel(): NodeProperty<TopicShapeType> {
if (!this.topicShapeModel)
this.topicShapeModel = {
getValue: () => this.uniqueOrNull((node) => node.getShapeType()),
setValue: (value: string) => this.designer.changeTopicShape(value),
getValue: () => this.uniqueOrNull((node) => node.getShapeType()) as TopicShapeType,
setValue: (value: TopicShapeType) => this.designer.changeTopicShape(value),
};
return this.topicShapeModel;
}

View File

@ -32,6 +32,10 @@ import CheckBoxOutlineBlankOutlinedIcon from '@mui/icons-material/CheckBoxOutlin
import HorizontalRuleOutlinedIcon from '@mui/icons-material/HorizontalRuleOutlined';
import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline';
import AddCircleOutlineOutlinedIcon from '@mui/icons-material/AddCircleOutlineOutlined';
import ShapeLineOutlined from '@mui/icons-material/ShapeLineOutlined';
import PolylineOutlined from '@mui/icons-material/PolylineOutlined';
import GestureOutlined from '@mui/icons-material/GestureOutlined';
import TimelineOutined from '@mui/icons-material/TimelineOutlined';
import Palette from '@mui/icons-material/Square';
import SquareOutlined from '@mui/icons-material/SquareOutlined';
@ -45,6 +49,7 @@ import IconPicker from '../action-widget/pane/icon-picker';
import FontFamilySelector from '../action-widget/button/font-family-selector';
import Editor from '../../classes/model/editor';
import { IntlShape } from 'react-intl';
import { LineType } from '@wisemapping/mindplot/src/components/ConnectionLine';
const keyTooltip = (msg: string, key: string): string => {
const isMac = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0;
@ -52,7 +57,7 @@ const keyTooltip = (msg: string, key: string): string => {
};
export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionConfig[] {
const toolbarValueModelBuilder = new NodePropertyValueModelBuilder(model.getDesigner());
const valueBulder = new NodePropertyValueModelBuilder(model.getDesigner());
// eslint-disable-next-line react-hooks/rules-of-hooks
const colorAndShapeToolbarConfiguration: ActionConfig = {
icon: <BrushOutlinedIcon />,
@ -67,8 +72,8 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
id: 'editor-panel.tooltip-topic-share-rectangle',
defaultMessage: 'Rectangle shape',
}),
onClick: () => toolbarValueModelBuilder.getTopicShapeModel().setValue('rectangle'),
selected: () => toolbarValueModelBuilder.getTopicShapeModel().getValue() === 'rectangle',
onClick: () => valueBulder.getTopicShapeModel().setValue('rectangle'),
selected: () => valueBulder.getTopicShapeModel().getValue() === 'rectangle',
},
{
icon: <CheckBoxOutlineBlankOutlinedIcon />,
@ -76,9 +81,8 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
id: 'editor-panel.tooltip-topic-share-rounded',
defaultMessage: 'Rounded shape',
}),
onClick: () => toolbarValueModelBuilder.getTopicShapeModel().setValue('rounded rectangle'),
selected: () =>
toolbarValueModelBuilder.getTopicShapeModel().getValue() === 'rounded rectangle',
onClick: () => valueBulder.getTopicShapeModel().setValue('rounded rectangle'),
selected: () => valueBulder.getTopicShapeModel().getValue() === 'rounded rectangle',
},
{
icon: <HorizontalRuleOutlinedIcon />,
@ -86,8 +90,8 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
id: 'editor-panel.tooltip-topic-share-line',
defaultMessage: 'Line shape',
}),
onClick: () => toolbarValueModelBuilder.getTopicShapeModel().setValue('line'),
selected: () => toolbarValueModelBuilder.getTopicShapeModel().getValue() === 'line',
onClick: () => valueBulder.getTopicShapeModel().setValue('line'),
selected: () => valueBulder.getTopicShapeModel().getValue() === 'line',
},
{
icon: <CircleOutlinedIcon />,
@ -95,14 +99,14 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
id: 'editor-panel.tooltip-topic-share-ellipse',
defaultMessage: 'Ellipse shape',
}),
onClick: () => toolbarValueModelBuilder.getTopicShapeModel().setValue('elipse'),
selected: () => toolbarValueModelBuilder.getTopicShapeModel().getValue() === 'elipse',
onClick: () => valueBulder.getTopicShapeModel().setValue('elipse'),
selected: () => valueBulder.getTopicShapeModel().getValue() === 'elipse',
},
null,
{
icon: () => (
<Palette
htmlColor={toolbarValueModelBuilder.getSelectedTopicColorModel().getValue() as string}
htmlColor={valueBulder.getSelectedTopicColorModel().getValue() as string}
></Palette>
),
tooltip: intl.formatMessage({
@ -115,7 +119,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
return (
<ColorPicker
closeModal={closeModal}
colorModel={toolbarValueModelBuilder.getSelectedTopicColorModel()}
colorModel={valueBulder.getSelectedTopicColorModel()}
></ColorPicker>
);
},
@ -124,9 +128,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
},
{
icon: () => (
<SquareOutlined
htmlColor={toolbarValueModelBuilder.getColorBorderModel().getValue() as string}
></SquareOutlined>
<SquareOutlined htmlColor={valueBulder.getColorBorderModel().getValue() as string} />
),
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-topic-border-color',
@ -138,7 +140,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
return (
<ColorPicker
closeModal={closeModal}
colorModel={toolbarValueModelBuilder.getColorBorderModel()}
colorModel={valueBulder.getColorBorderModel()}
></ColorPicker>
);
},
@ -149,6 +151,46 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
disabled: () => model.getDesignerModel().filterSelectedTopics().length === 0,
};
const connectionStyleConfiguration: ActionConfig = {
icon: <ShapeLineOutlined />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-connection-style',
defaultMessage: 'Connection Style',
}),
options: [
{
icon: <PolylineOutlined />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-connection-style-polyline',
defaultMessage: 'Polyline',
}),
onClick: () => valueBulder.getConnectionStyleModel().setValue(LineType.POLYLINE_MIDDLE),
selected: () =>
valueBulder.getConnectionStyleModel().getValue() === LineType.POLYLINE_MIDDLE,
},
{
icon: <TimelineOutined />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-connection-style-polyline-curved',
defaultMessage: 'Polyline Curved',
}),
onClick: () => valueBulder.getConnectionStyleModel().setValue(LineType.POLYLINE_CURVED),
selected: () =>
valueBulder.getConnectionStyleModel().getValue() === LineType.POLYLINE_CURVED,
},
{
icon: <GestureOutlined />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-connection-style-curved',
defaultMessage: 'Curved',
}),
onClick: () => valueBulder.getConnectionStyleModel().setValue(LineType.SIMPLE_CURVED),
selected: () => valueBulder.getConnectionStyleModel().getValue() === LineType.SIMPLE_CURVED,
},
],
disabled: () => model.getDesignerModel().filterSelectedTopics().length === 0,
};
/**
* submenu to manipulate node font
*/
@ -160,9 +202,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
}),
options: [
{
render: () => (
<FontFamilySelector fontFamilyModel={toolbarValueModelBuilder.getFontFamilyModel()} />
),
render: () => <FontFamilySelector fontFamilyModel={valueBulder.getFontFamilyModel()} />,
},
null,
{
@ -171,8 +211,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
id: 'editor-panel.tooltip-topic-font-bigger',
defaultMessage: 'Bigger',
}),
onClick: () =>
toolbarValueModelBuilder.getFontSizeModel().switchValue(SwitchValueDirection.up),
onClick: () => valueBulder.getFontSizeModel().switchValue(SwitchValueDirection.up),
},
{
icon: <TextDecreaseOutlinedIcon></TextDecreaseOutlinedIcon>,
@ -180,8 +219,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
id: 'editor-panel.tooltip-topic-font-smaller',
defaultMessage: 'Smaller',
}),
onClick: () =>
toolbarValueModelBuilder.getFontSizeModel().switchValue(SwitchValueDirection.down),
onClick: () => valueBulder.getFontSizeModel().switchValue(SwitchValueDirection.down),
},
null,
{
@ -193,8 +231,8 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
}),
'B',
),
onClick: toolbarValueModelBuilder.fontWeigthModel().switchValue,
selected: () => toolbarValueModelBuilder.fontWeigthModel().getValue() === 'bold',
onClick: valueBulder.fontWeigthModel().switchValue,
selected: () => valueBulder.fontWeigthModel().getValue() === 'bold',
},
{
icon: <FormatItalicIcon />,
@ -205,13 +243,11 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
}),
'I',
),
onClick: toolbarValueModelBuilder.getFontStyleModel().switchValue,
selected: () => toolbarValueModelBuilder.getFontStyleModel().getValue() === 'italic',
onClick: valueBulder.getFontStyleModel().switchValue,
selected: () => valueBulder.getFontStyleModel().getValue() === 'italic',
},
{
icon: () => (
<Palette htmlColor={toolbarValueModelBuilder.getFontColorModel().getValue() as string} />
),
icon: () => <Palette htmlColor={valueBulder.getFontColorModel().getValue() as string} />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-topic-font-color',
defaultMessage: 'Color',
@ -222,7 +258,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
return (
<ColorPicker
closeModal={closeModal}
colorModel={toolbarValueModelBuilder.getFontColorModel()}
colorModel={valueBulder.getFontColorModel()}
></ColorPicker>
);
},
@ -261,10 +297,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
options: [
{
render: (closeModal) => (
<TopicLink
closeModal={closeModal}
urlModel={toolbarValueModelBuilder.getLinkModel()}
></TopicLink>
<TopicLink closeModal={closeModal} urlModel={valueBulder.getLinkModel()}></TopicLink>
),
},
],
@ -285,10 +318,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
{
tooltip: 'Node note',
render: (closeModal) => (
<TopicNote
closeModal={closeModal}
noteModel={toolbarValueModelBuilder.getNoteModel()}
></TopicNote>
<TopicNote closeModal={closeModal} noteModel={valueBulder.getNoteModel()}></TopicNote>
),
},
],
@ -312,10 +342,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
defaultMessage: 'Add Icon',
}),
render: (closeModal) => (
<IconPicker
triggerClose={closeModal}
iconModel={toolbarValueModelBuilder.getTopicIconModel()}
/>
<IconPicker triggerClose={closeModal} iconModel={valueBulder.getTopicIconModel()} />
),
},
],
@ -350,6 +377,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
editIconConfiguration,
editNoteConfiguration,
editLinkUrlConfiguration,
connectionStyleConfiguration,
addRelationConfiguration,
];
}

View File

@ -25,10 +25,9 @@ import Workspace from './Workspace';
// eslint-disable-next-line no-shadow
export enum LineType {
SIMPLE,
POLYLINE,
CURVED,
SIMPLE_CURVED,
POLYLINE_MIDDLE,
POLYLINE_CURVED,
}
class ConnectionLine {
@ -52,11 +51,18 @@ class ConnectionLine {
const line = this._createLine(type);
const strokeColor = ConnectionLine.getStrokeColor();
if (type === LineType.SIMPLE_CURVED) {
line.setStroke(1, 'solid', strokeColor, 1);
line.setFill(strokeColor, 1);
} else {
line.setStroke(2, 'solid', strokeColor, 1);
switch (type) {
case LineType.POLYLINE_MIDDLE:
case LineType.POLYLINE_CURVED:
line.setStroke(1, 'solid', strokeColor, 1);
break;
case LineType.SIMPLE_CURVED:
line.setStroke(1, 'solid', strokeColor, 1);
line.setFill(strokeColor, 2);
break;
default:
line.setStroke(2, 'solid', strokeColor, 1);
}
// Set line styles ...
@ -77,19 +83,18 @@ class ConnectionLine {
this._lineType = lineType;
let line: ConnectionLine;
switch (lineType) {
case LineType.POLYLINE:
case LineType.POLYLINE_MIDDLE:
line = new PolyLine();
(line as PolyLine).setStyle('MiddleStraight');
break;
case LineType.CURVED:
line = new CurvedLine();
case LineType.POLYLINE_CURVED:
line = new PolyLine();
(line as PolyLine).setStyle('Curved');
break;
case LineType.SIMPLE_CURVED:
line = new CurvedLine();
(line as CurvedLine).setStyle(CurvedLine.SIMPLE_LINE);
break;
case LineType.SIMPLE:
line = new Line();
break;
default:
throw new Error(`Unexpected line type. ${lineType}`);
}

View File

@ -56,6 +56,8 @@ import DragTopic from './DragTopic';
import CentralTopic from './CentralTopic';
import FeatureType from './model/FeatureType';
import WidgetManager from './WidgetManager';
import { TopicShapeType } from './model/INodeModel';
import { LineType } from './ConnectionLine';
class Designer extends Events {
private _mindmap: Mindmap;
@ -480,6 +482,11 @@ class Designer extends Events {
if (backgroundColor) {
targetModel.setBackgroundColor(backgroundColor);
}
const connectType = sourceModel.getConnectionStyle();
if ($defined(connectType)) {
targetModel.setConnectionStyle(connectType!);
}
}
private _createChildModel(topic: Topic, mousePos: Point = null): NodeModel {
@ -860,7 +867,7 @@ class Designer extends Events {
}
}
changeTopicShape(shape: string) {
changeTopicShape(shape: TopicShapeType): void {
const validateFunc = (topic: Topic) =>
!(topic.getType() === 'CentralTopic' && shape === 'line');
@ -871,6 +878,16 @@ class Designer extends Events {
}
}
changeConnectionStyle(type: LineType): void {
const validateFunc = (topic: Topic) => !topic.isCentralTopic();
const validateError = 'Central Topic can not be changed to line figure.';
const topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError);
if (topicsIds.length > 0) {
this._actionDispatcher.changeConnectionStyleToTopic(topicsIds, type);
}
}
changeFontWeight(): void {
const topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {

View File

@ -38,6 +38,7 @@ import FeatureType from './model/FeatureType';
import PositionType from './PositionType';
import { PivotType } from './RelationshipControlPoints';
import { TopicShapeType } from './model/INodeModel';
import { LineType } from './ConnectionLine';
class StandaloneActionDispatcher extends ActionDispatcher {
private _actionRunner: DesignerActionRunner;
@ -136,7 +137,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
const result = topic.getFontFamily();
topic.setFontFamily(commandFontFamily, true);
topic.adjustShapes();
topic.redraw();
return result;
};
@ -201,7 +202,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
const result = topic.getFontSize();
topic.setFontSize(commandSize, true);
topic.adjustShapes();
topic.redraw();
return result;
};
@ -209,14 +210,13 @@ class StandaloneActionDispatcher extends ActionDispatcher {
this.execute(command);
}
/** */
changeShapeTypeToTopic(topicsIds: number[], shapeType: string) {
changeShapeTypeToTopic(topicsIds: number[], shapeType: TopicShapeType) {
$assert(topicsIds, 'topicsIds can not be null');
$assert(shapeType, 'shapeType can not be null');
const commandFunc = (topic: Topic, commandShapeType: string) => {
const commandFunc = (topic: Topic, commandShapeType: TopicShapeType) => {
const result = topic.getShapeType();
topic.setShapeType(commandShapeType as TopicShapeType);
topic.setShapeType(commandShapeType);
return result;
};
@ -224,7 +224,17 @@ class StandaloneActionDispatcher extends ActionDispatcher {
this.execute(command);
}
/** */
changeConnectionStyleToTopic(topicsIds: number[], lineType: LineType) {
const commandFunc = (topic: Topic, commandShapeType: LineType) => {
const result = topic.getConnectionStyle();
topic.setConnectionStyle(commandShapeType);
return result;
};
const command = new GenericFunctionCommand(commandFunc, topicsIds, lineType);
this.execute(command);
}
changeFontWeightToTopic(topicsIds: number[]) {
$assert(topicsIds, 'topicsIds can not be null');
@ -232,8 +242,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
const result = topic.getFontWeight();
const weight = result === 'bold' ? 'normal' : 'bold';
topic.setFontWeight(weight, true);
topic.adjustShapes();
topic.redraw();
return result;
};

View File

@ -23,7 +23,7 @@ import NodeGraph from './NodeGraph';
import TopicConfig from './TopicConfig';
import TopicStyle from './TopicStyle';
import TopicFeatureFactory from './TopicFeature';
import ConnectionLine from './ConnectionLine';
import ConnectionLine, { LineType } from './ConnectionLine';
import IconGroup from './IconGroup';
import EventBus from './layout/EventBus';
import ShirinkConnector from './ShrinkConnector';
@ -64,7 +64,7 @@ abstract class Topic extends NodeGraph {
private _connector: ShirinkConnector;
private _outgoingLine: Line;
private _outgoingLine: ConnectionLine | null;
constructor(model: NodeModel, options) {
super(model, options);
@ -140,7 +140,7 @@ abstract class Topic extends NodeGraph {
// Move iconGroup to front ...
const iconGroup = this.getIconGroup();
if ($defined(iconGroup)) {
if (iconGroup) {
iconGroup.moveToFront();
}
@ -161,6 +161,15 @@ abstract class Topic extends NodeGraph {
return result;
}
getConnectionStyle(): LineType {
const model = this.getModel();
let result = model.getConnectionStyle();
if (!result) {
result = TopicStyle.defaultConnectionType(this);
}
return result;
}
private _removeInnerShape(): ElementClass {
const group = this.get2DElement();
const innerShape = this.getInnerShape();
@ -192,7 +201,7 @@ abstract class Topic extends NodeGraph {
return this._innerShape;
}
_buildShape(attributes, shapeType: TopicShapeType): ElementClass {
protected _buildShape(attributes, shapeType: TopicShapeType): ElementClass {
$assert(attributes, 'attributes can not be null');
$assert(shapeType, 'shapeType can not be null');
@ -346,7 +355,7 @@ abstract class Topic extends NodeGraph {
featureModel.getType() === TopicFeatureFactory.EmojiIcon.id;
iconGroup.addIcon(result, isIcon && !this.isReadOnly());
this.adjustShapes();
this.redraw();
return result;
}
@ -368,7 +377,7 @@ abstract class Topic extends NodeGraph {
if ($defined(iconGroup)) {
iconGroup.removeIconByModel(featureModel);
}
this.adjustShapes();
this.redraw();
}
addRelationship(relationship: Relationship) {
@ -414,7 +423,7 @@ abstract class Topic extends NodeGraph {
const model = this.getModel();
model.setFontFamily(value);
}
this.adjustShapes();
this.redraw();
}
setFontSize(value: number, updateModel?: boolean) {
@ -425,7 +434,7 @@ abstract class Topic extends NodeGraph {
const model = this.getModel();
model.setFontSize(value);
}
this.adjustShapes();
this.redraw();
}
setFontStyle(value: string, updateModel?: boolean) {
@ -435,7 +444,7 @@ abstract class Topic extends NodeGraph {
const model = this.getModel();
model.setFontStyle(value);
}
this.adjustShapes();
this.redraw();
}
setFontWeight(value: string, updateModel?: boolean) {
@ -445,7 +454,7 @@ abstract class Topic extends NodeGraph {
const model = this.getModel();
model.setFontWeight(value);
}
this.adjustShapes();
this.redraw();
}
getFontWeight() {
@ -525,7 +534,7 @@ abstract class Topic extends NodeGraph {
this._setText(text, true);
}
this.adjustShapes();
this.redraw();
}
getText(): string {
@ -538,6 +547,13 @@ abstract class Topic extends NodeGraph {
this._setBackgroundColor(color, true);
}
setConnectionStyle(type: LineType): void {
this.getModel().setConnectionStyle(type);
// Needs to change change all the lines types. Outgoing are part of the children.
this.getChildren().map((topic: Topic) => topic.redraw());
}
private _setBackgroundColor(color: string, updateModel: boolean) {
const innerShape = this.getInnerShape();
innerShape.setFill(color);
@ -857,7 +873,7 @@ abstract class Topic extends NodeGraph {
private _updateConnectionLines(): void {
// Update this to parent line ...
const outgoingLine = this.getOutgoingLine();
if ($defined(outgoingLine)) {
if (outgoingLine) {
outgoingLine.redraw();
}
@ -880,13 +896,13 @@ abstract class Topic extends NodeGraph {
}
setVisibility(value: boolean, fade = 0): void {
this._setTopicVisibility(value, fade);
this.setTopicVisibility(value, fade);
// Hide all children...
this._setChildrenVisibility(value, fade);
// If there there are connection to the node, topic must be hidden.
this._setRelationshipLinesVisibility(value, fade);
this.setRelationshipLinesVisibility(value, fade);
// If it's connected, the connection must be rendered.
const outgoingLine = this.getOutgoingLine();
@ -895,8 +911,7 @@ abstract class Topic extends NodeGraph {
}
}
/** */
moveToBack(): void {
protected moveToBack(): void {
// Update relationship lines
this._relationships.forEach((r) => r.moveToBack());
@ -908,8 +923,7 @@ abstract class Topic extends NodeGraph {
this.get2DElement().moveToBack();
}
/** */
moveToFront(): void {
protected moveToFront(): void {
this.get2DElement().moveToFront();
const connector = this.getShrinkConnector();
if (connector) {
@ -919,13 +933,12 @@ abstract class Topic extends NodeGraph {
this._relationships.forEach((r) => r.moveToFront());
}
/** */
isVisible(): boolean {
const elem = this.get2DElement();
return elem.isVisible();
}
private _setRelationshipLinesVisibility(value: boolean, fade = 0): void {
private setRelationshipLinesVisibility(value: boolean, fade = 0): void {
this._relationships.forEach((relationship) => {
const sourceTopic = relationship.getSourceTopic();
const targetTopic = relationship.getTargetTopic();
@ -941,7 +954,7 @@ abstract class Topic extends NodeGraph {
});
}
private _setTopicVisibility(value: boolean, fade = 0) {
private setTopicVisibility(value: boolean, fade = 0) {
const elem = this.get2DElement();
elem.setVisibility(value, fade);
@ -960,7 +973,6 @@ abstract class Topic extends NodeGraph {
textShape.setVisibility(this.getShapeType() !== 'image' ? value : false, fade);
}
/** */
setOpacity(opacity: number): void {
const elem = this.get2DElement();
elem.setOpacity(opacity);
@ -1088,7 +1100,6 @@ abstract class Topic extends NodeGraph {
model.setOrder(value);
}
/** */
connectTo(targetTopic: Topic, workspace: Workspace) {
$assert(!this._outgoingLine, 'Could not connect an already connected node');
$assert(targetTopic !== this, 'Circular connection are not allowed');
@ -1105,7 +1116,7 @@ abstract class Topic extends NodeGraph {
childModel.connectTo(targetModel);
// Create a connection line ...
const outgoingLine = new ConnectionLine(this, targetTopic);
const outgoingLine = this.createConnectionLine(targetTopic);
outgoingLine.setVisibility(false);
this._outgoingLine = outgoingLine;
@ -1144,7 +1155,13 @@ abstract class Topic extends NodeGraph {
}
}
abstract updateTopicShape(targetTopic: Topic);
private createConnectionLine(targetTopic: Topic): ConnectionLine {
const type: LineType = targetTopic.getConnectionStyle();
console.log(`redraw ...: ${type}`);
return new ConnectionLine(this, targetTopic, type);
}
abstract updateTopicShape(targetTopic: Topic): void;
append(child: Topic): void {
const children = this.getChildren();
@ -1195,7 +1212,7 @@ abstract class Topic extends NodeGraph {
}
}
this._isInWorkspace = true;
this.adjustShapes();
this.redraw();
}
/** */
@ -1220,7 +1237,29 @@ abstract class Topic extends NodeGraph {
return result;
}
adjustShapes(): void {
private redrawConnection(): boolean {
let result = false;
if (this._isInWorkspace) {
// Adjust connection line if there is a change in the parent...
const connStyleChanged =
this._outgoingLine?.getLineType() !== this.getParent()?.getConnectionStyle();
if (this._outgoingLine && connStyleChanged) {
// Todo: Review static reference ...
const workspace = designer.getWorkSpace();
this._outgoingLine.removeFromWorkspace(workspace);
const targetTopic = this.getOutgoingConnectedTopic()!;
this._outgoingLine = this.createConnectionLine(targetTopic);
this._outgoingLine.setVisibility(this.isVisible());
workspace.append(this._outgoingLine);
result = true;
}
}
return result;
}
redraw(): void {
if (this._isInWorkspace) {
const textShape = this.getTextShape();
if (this.getShapeType() !== 'image') {
@ -1241,13 +1280,9 @@ abstract class Topic extends NodeGraph {
const iconGroupWith = iconGroup.getSize().width;
const topicWith = iconGroupWith + 2 * textIconSpacing + textWidth + padding * 2;
this.setSize(
{
width: topicWith,
height: topicHeight,
},
false,
);
// Update connections ...
const changed = this.redrawConnection();
this.setSize({ width: topicWith, height: topicHeight }, changed);
// Adjust all topic elements positions ...
const yPosition = Math.round((topicHeight - textHeight) / 2);

View File

@ -16,20 +16,23 @@
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import { LineType } from './ConnectionLine';
import { $msg } from './Messages';
import { TopicShapeType } from './model/INodeModel';
import Topic from './Topic';
type FontStlye = {
font: string;
size: number;
style: string;
weight: string;
color: string;
};
type TopicStyleType = {
borderColor: string;
backgroundColor: string;
fontStyle: {
font: string;
size: number;
style: string;
weight: string;
color: string;
};
connectionStyle: LineType;
fontStyle: FontStlye;
msgKey: string;
shapeType: TopicShapeType;
};
@ -45,6 +48,7 @@ const TopicDefaultStyles = {
weight: 'bold',
color: '#ffffff',
},
connectionStyle: LineType.SIMPLE_CURVED,
msgKey: 'CENTRAL_TOPIC',
shapeType: 'rounded rectangle' as TopicShapeType,
},
@ -58,6 +62,7 @@ const TopicDefaultStyles = {
weight: 'normal',
color: 'rgb(82,92,97)',
},
connectionStyle: LineType.SIMPLE_CURVED,
msgKey: 'MAIN_TOPIC',
shapeType: 'line' as TopicShapeType,
},
@ -71,6 +76,7 @@ const TopicDefaultStyles = {
weight: 'normal',
color: 'rgb(82,92,97)',
},
connectionStyle: LineType.SIMPLE_CURVED,
msgKey: 'SUB_TOPIC',
shapeType: 'line' as TopicShapeType,
},
@ -86,6 +92,7 @@ const TopicDefaultStyles = {
color: 'rgb(82,92,97)',
},
msgKey: 'ISOLATED_TOPIC',
connectionStyle: LineType.SIMPLE_CURVED,
shapeType: 'line' as TopicShapeType,
},
};
@ -112,30 +119,34 @@ class TopicStyle {
return result;
}
static defaultText(topic: Topic) {
static defaultText(topic: Topic): string {
const { msgKey } = this._getStyles(topic);
return $msg(msgKey);
}
static defaultFontStyle(topic: Topic) {
static defaultFontStyle(topic: Topic): FontStlye {
return this._getStyles(topic).fontStyle;
}
static defaultBackgroundColor(topic: Topic) {
static defaultBackgroundColor(topic: Topic): string {
return this._getStyles(topic).backgroundColor;
}
static defaultBorderColor(topic: Topic) {
static defaultBorderColor(topic: Topic): string {
return this._getStyles(topic).borderColor;
}
static getInnerPadding(topic: Topic) {
static getInnerPadding(topic: Topic): number {
return Math.round(topic.getTextShape().getFontHeight() * 0.5);
}
static defaultShapeType(topic: Topic) {
static defaultShapeType(topic: Topic): TopicShapeType {
return this._getStyles(topic).shapeType;
}
static defaultConnectionType(topic: Topic): LineType {
return this._getStyles(topic).connectionStyle;
}
}
export default TopicStyle;

View File

@ -17,6 +17,7 @@
* limitations under the License.
*/
import { $assert, $defined } from '@wisemapping/core-js';
import { LineType } from '../ConnectionLine';
import PositionType from '../PositionType';
import FeatureModel from './FeatureModel';
import Mindmap from './Mindmap';
@ -132,12 +133,10 @@ abstract class INodeModel {
mindmap.disconnect(this);
}
/** */
getShapeType(): TopicShapeType {
return this.getProperty('shapeType') as TopicShapeType;
}
/** */
setShapeType(type: string) {
this.putProperty('shapeType', type);
}
@ -162,7 +161,6 @@ abstract class INodeModel {
return this.getProperty('fontFamily') as string;
}
/** */
setFontStyle(fontStyle: string) {
this.putProperty('fontStyle', fontStyle);
}
@ -179,7 +177,7 @@ abstract class INodeModel {
return this.getProperty('fontWeight');
}
setFontColor(color: string) {
setFontColor(color: string): void {
this.putProperty('fontColor', color);
}
@ -187,7 +185,7 @@ abstract class INodeModel {
return this.getProperty('fontColor') as string;
}
setFontSize(size: number) {
setFontSize(size: number): void {
this.putProperty('fontSize', size);
}
@ -219,10 +217,18 @@ abstract class INodeModel {
/**
* @return {Boolean} true if the children nodes are hidden by the shrink option
*/
setChildrenShrunken(value: boolean) {
setChildrenShrunken(value: boolean): void {
this.putProperty('shrunken', value);
}
setConnectionStyle(type: LineType): void {
this.putProperty('connectionStyle', type);
}
getConnectionStyle(): LineType | null {
return this.getProperty('connectionStyle') as LineType;
}
isNodeModel(): boolean {
return true;
}
@ -234,7 +240,7 @@ abstract class INodeModel {
return this.getParent() != null;
}
abstract append(node): void;
abstract append(node: INodeModel): void;
/**
* lets the mindmap handle the connect node operation

View File

@ -28,7 +28,7 @@ class RelationshipModel {
private _targetTopicId: number;
private _lineType: number;
private _lineType: LineType;
private _srcCtrlPoint: Point;
@ -67,11 +67,11 @@ class RelationshipModel {
return this._id;
}
getLineType(): number {
getLineType(): LineType {
return this._lineType;
}
setLineType(lineType: number) {
setLineType(lineType: LineType) {
this._lineType = lineType;
}

View File

@ -18,13 +18,13 @@
import { $assert, $defined, createDocument } from '@wisemapping/core-js';
import { Point } from '@wisemapping/web2d';
import Mindmap from '../model/Mindmap';
import { LineType } from '../ConnectionLine';
import FeatureModelFactory from '../model/FeatureModelFactory';
import NodeModel from '../model/NodeModel';
import RelationshipModel from '../model/RelationshipModel';
import XMLMindmapSerializer from './XMLMindmapSerializer';
import FeatureType from '../model/FeatureType';
import emojiToIconMap from './iconToEmoji.json';
import { LineType } from '../ConnectionLine';
class XMLSerializerTango implements XMLMindmapSerializer {
private static MAP_ROOT_NODE = 'map';
@ -152,6 +152,11 @@ class XMLSerializerTango implements XMLMindmapSerializer {
parentTopic.setAttribute('brColor', brColor);
}
const connectionStyle = topic.getConnectionStyle();
if ($defined(connectionStyle)) {
parentTopic.setAttribute('connStyle', `${connectionStyle}`);
}
const metadata = topic.getMetadata();
if ($defined(metadata)) {
parentTopic.setAttribute('metadata', metadata);
@ -206,18 +211,13 @@ class XMLSerializerTango implements XMLMindmapSerializer {
const lineType = relationship.getLineType();
result.setAttribute('lineType', lineType.toString());
if (lineType === LineType.CURVED || lineType === LineType.SIMPLE_CURVED) {
if ($defined(relationship.getSrcCtrlPoint())) {
const srcPoint = relationship.getSrcCtrlPoint();
result.setAttribute('srcCtrlPoint', `${Math.round(srcPoint.x)},${Math.round(srcPoint.y)}`);
}
if ($defined(relationship.getDestCtrlPoint())) {
const destPoint = relationship.getDestCtrlPoint();
result.setAttribute(
'destCtrlPoint',
`${Math.round(destPoint.x)},${Math.round(destPoint.y)}`,
);
}
if ($defined(relationship.getSrcCtrlPoint())) {
const srcPoint = relationship.getSrcCtrlPoint();
result.setAttribute('srcCtrlPoint', `${Math.round(srcPoint.x)},${Math.round(srcPoint.y)}`);
}
if ($defined(relationship.getDestCtrlPoint())) {
const destPoint = relationship.getDestCtrlPoint();
result.setAttribute('destCtrlPoint', `${Math.round(destPoint.x)},${Math.round(destPoint.y)}`);
}
result.setAttribute('endArrow', String(relationship.getEndArrow()));
result.setAttribute('startArrow', String(relationship.getStartArrow()));
@ -345,6 +345,12 @@ class XMLSerializerTango implements XMLMindmapSerializer {
topic.setBackgroundColor(bgColor);
}
const connStyle = domElem.getAttribute('connStyle');
if ($defined(connStyle) && connStyle) {
const lineType = Number.parseInt(connStyle, 10) as LineType;
topic.setConnectionStyle(lineType);
}
const borderColor = domElem.getAttribute('brColor');
if (borderColor) {
topic.setBorderColor(borderColor);

View File

@ -99,7 +99,7 @@ class PolyLinePeer extends ElementPeer {
if (y2 < y1) {
signy = -1;
}
const path = `${x1}, ${y1} ${middlex - 10 * signx}, ${y1} ${middlex}, ${y1 + 10 * signy
const path = `${x1}, ${y1} ${(middlex - 10 * signx).toFixed(0)}, ${y1} ${(middlex).toFixed(0)}, ${y1 + 10 * signy
} ${middlex}, ${y2 - 10 * signy} ${middlex + 10 * signx}, ${y2} ${x2}, ${y2}`;
this._native.setAttribute('points', path);
}
@ -112,7 +112,7 @@ class PolyLinePeer extends ElementPeer {
const y2 = this._y2;
if ($defined(x1) && $defined(x2) && $defined(y1) && $defined(y2)) {
const diff = x2 - x1;
const middlex = diff / 2 + x1;
const middlex = (diff * 0.75 + x1).toFixed(0);
const path = `${x1}, ${y1} ${middlex}, ${y1} ${middlex}, ${y1} ${middlex}, ${y2} ${middlex}, ${y2} ${x2}, ${y2}`;
this._native.setAttribute('points', path);
}

View File

@ -4,6 +4,9 @@ context('Editor Page', () => {
});
it('page loaded', () => {
// Wait for load complate ...
cy.get('[aria-label="vortex-loading"]').should('not.exist');
cy.matchImageSnapshot('editor-page');
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB