Add connection color

This commit is contained in:
Paulo Gustavo Veiga 2022-12-31 01:50:41 -08:00
parent f2c9762446
commit f6b7d19cb1
15 changed files with 338 additions and 219 deletions

View File

@ -22,6 +22,7 @@ class NodePropertyBuilder {
private topicShapeModel: NodeProperty<TopicShapeType>;
private topicIconModel: NodeProperty<string>;
private connetionStyleModel: NodeProperty<LineType>;
private connectionColoreModel: NodeProperty<string>;
private noteModel: NodeProperty<string>;
private linkModel: NodeProperty<string>;
@ -137,10 +138,6 @@ class NodePropertyBuilder {
return this.fontColorModel;
}
/**
*
* @returns model to get and set topic icon
*/
getTopicIconModel(): NodeProperty<string> {
if (!this.topicIconModel)
this.topicIconModel = {
@ -204,6 +201,15 @@ class NodePropertyBuilder {
return this.connetionStyleModel;
}
getConnectionColorModel(): NodeProperty<string> {
if (!this.connectionColoreModel)
this.connectionColoreModel = {
getValue: () => this.selectedTopic()?.getConnectionColor(),
setValue: (value: string) => this.designer.changeConnectionColor(value),
};
return this.connectionColoreModel;
}
getTopicShapeModel(): NodeProperty<TopicShapeType> {
if (!this.topicShapeModel)
this.topicShapeModel = {

View File

@ -36,6 +36,7 @@ import PolylineOutlined from '@mui/icons-material/PolylineOutlined';
import GestureOutlined from '@mui/icons-material/GestureOutlined';
import TimelineOutined from '@mui/icons-material/TimelineOutlined';
import ShareOutlined from '@mui/icons-material/ShareOutlined';
import SwapCallsOutlined from '@mui/icons-material/SwapCallsOutlined';
import Palette from '@mui/icons-material/Square';
import SquareOutlined from '@mui/icons-material/SquareOutlined';
@ -104,11 +105,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
},
null,
{
icon: () => (
<Palette
htmlColor={valueBulder.getSelectedTopicColorModel().getValue() as string}
></Palette>
),
icon: () => <Palette htmlColor={valueBulder.getSelectedTopicColorModel().getValue()} />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-topic-fill-color',
defaultMessage: 'Fill color',
@ -120,16 +117,14 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
<ColorPicker
closeModal={closeModal}
colorModel={valueBulder.getSelectedTopicColorModel()}
></ColorPicker>
/>
);
},
},
],
},
{
icon: () => (
<SquareOutlined htmlColor={valueBulder.getColorBorderModel().getValue() as string} />
),
icon: () => <SquareOutlined htmlColor={valueBulder.getColorBorderModel().getValue()} />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-topic-border-color',
defaultMessage: 'Border color',
@ -141,7 +136,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
<ColorPicker
closeModal={closeModal}
colorModel={valueBulder.getColorBorderModel()}
></ColorPicker>
/>
);
},
},
@ -158,15 +153,6 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
defaultMessage: 'Connection Style',
}),
options: [
{
icon: <GestureOutlined />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-connection-style-curved-thin',
defaultMessage: 'Thin Curved',
}),
onClick: () => valueBulder.getConnectionStyleModel().setValue(LineType.THICK_CURVED),
selected: () => valueBulder.getConnectionStyleModel().getValue() === LineType.THICK_CURVED,
},
{
icon: <GestureOutlined />,
tooltip: intl.formatMessage({
@ -176,6 +162,15 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
onClick: () => valueBulder.getConnectionStyleModel().setValue(LineType.THICK_CURVED),
selected: () => valueBulder.getConnectionStyleModel().getValue() === LineType.THICK_CURVED,
},
{
icon: <SwapCallsOutlined />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-connection-style-curved-thin',
defaultMessage: 'Thin Curved',
}),
onClick: () => valueBulder.getConnectionStyleModel().setValue(LineType.THIN_CURVED),
selected: () => valueBulder.getConnectionStyleModel().getValue() === LineType.THIN_CURVED,
},
{
icon: <PolylineOutlined />,
tooltip: intl.formatMessage({
@ -196,30 +191,30 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
selected: () =>
valueBulder.getConnectionStyleModel().getValue() === LineType.POLYLINE_CURVED,
},
// null,
// {
// icon: () => <Palette htmlColor={valueBulder.getFontColorModel().getValue() as string} />,
// tooltip: intl.formatMessage({
// id: 'editor-panel.tooltip-connection-style-color',
// defaultMessage: 'Color',
// }),
// options: [
// {
// render: (closeModal) => {
// return (
// <ColorPicker
// closeModal={closeModal}
// colorModel={valueBulder.getFontColorModel()}
// />
// );
// },
// },
// ],
// },
null,
{
icon: () => <Palette htmlColor={valueBulder.getConnectionColorModel().getValue()} />,
tooltip: intl.formatMessage({
id: 'editor-panel.tooltip-connection-color',
defaultMessage: 'Color',
}),
options: [
{
render: (closeModal) => {
return (
<ColorPicker
closeModal={closeModal}
colorModel={valueBulder.getConnectionColorModel()}
/>
);
},
},
],
},
],
disabled: () => {
const selected = model.getDesignerModel().filterSelectedTopics();
return selected.length === 0 || (selected.length === 1 && selected[0].isCentralTopic());
return selected.length === 0;
},
};
@ -278,6 +273,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
onClick: valueBulder.getFontStyleModel().switchValue,
selected: () => valueBulder.getFontStyleModel().getValue() === 'italic',
},
null,
{
icon: () => <Palette htmlColor={valueBulder.getFontColorModel().getValue() as string} />,
tooltip: intl.formatMessage({
@ -347,7 +343,7 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
{
tooltip: 'Node note',
render: (closeModal) => (
<TopicNote closeModal={closeModal} noteModel={valueBulder.getNoteModel()}></TopicNote>
<TopicNote closeModal={closeModal} noteModel={valueBulder.getNoteModel()} />
),
},
],
@ -403,10 +399,10 @@ export function buildEditorPanelConfig(model: Editor, intl: IntlShape): ActionCo
deleteNodeToolbarConfiguration,
colorAndShapeToolbarConfiguration,
fontFormatToolbarConfiguration,
connectionStyleConfiguration,
editIconConfiguration,
editNoteConfiguration,
editLinkUrlConfiguration,
connectionStyleConfiguration,
addRelationConfiguration,
];
}

View File

@ -37,23 +37,20 @@ class ConnectionLine {
protected _lineType: LineType;
protected _line2d: Line;
protected _line: Line;
private _type: LineType;
private _color: string;
constructor(sourceNode: Topic, targetNode: Topic, type: LineType = LineType.THIN_CURVED) {
$assert(targetNode, 'parentNode node can not be null');
$assert(sourceNode, 'childNode node can not be null');
$assert(sourceNode !== targetNode, 'Circular connection');
this._targetTopic = targetNode;
this._sourceTopic = sourceNode;
this._type = type;
const line = this._createLine(type);
// Set line styles ...
this._line2d = line;
this._line = this.createLine(type);
this.updateColor();
}
private _getCtrlPoints(sourceNode: Topic, targetNode: Topic) {
@ -66,53 +63,68 @@ class ConnectionLine {
];
}
protected _createLine(lineType: LineType): ConnectionLine {
protected createLine(lineType: LineType): ConnectionLine {
this._lineType = lineType;
let line: ConnectionLine;
const strokeColor = ConnectionLine.getStrokeColor();
switch (lineType) {
case LineType.POLYLINE_MIDDLE:
line = new PolyLine();
(line as PolyLine).setStyle('MiddleStraight');
(line as PolyLine).setStroke(1, 'solid', strokeColor, 1);
break;
case LineType.POLYLINE_CURVED:
line = new PolyLine();
(line as PolyLine).setStyle('Curved');
(line as PolyLine).setStroke(1, 'solid', strokeColor, 1);
break;
case LineType.THIN_CURVED:
line = new CurvedLine();
(line as CurvedLine).setStroke(1, 'solid', strokeColor, 1);
(line as CurvedLine).setFill(strokeColor, 1);
break;
case LineType.THICK_CURVED:
line = new CurvedLine();
(line as CurvedLine).setStroke(1, 'solid', strokeColor, 1);
(line as CurvedLine).setFill(strokeColor, 1);
(line as CurvedLine).setWidth(this._targetTopic.isCentralTopic() ? 15 : 3);
break;
default:
throw new Error(`Unexpected line type. ${lineType}`);
}
return line;
}
private updateColor(): void {
const color = this._targetTopic.getConnectionColor();
this._color = color;
switch (this._lineType) {
case LineType.POLYLINE_MIDDLE:
this._line.setStroke(1, 'solid', color, 1);
break;
case LineType.POLYLINE_CURVED:
this._line.setStroke(1, 'solid', color, 1);
break;
case LineType.THIN_CURVED:
this._line.setStroke(1, 'solid', color, 1);
this._line.setFill(color, 1);
break;
case LineType.THICK_CURVED:
this._line.setStroke(1, 'solid', color, 1);
this._line.setFill(color, 1);
break;
default:
throw new Error(`Unexpected line type. ${this._lineType}`);
}
}
setVisibility(value: boolean, fade = 0): void {
this._line2d.setVisibility(value, fade);
this._line.setVisibility(value, fade);
}
isVisible(): boolean {
return this._line2d.isVisible();
return this._line.isVisible();
}
setOpacity(opacity: number): void {
this._line2d.setOpacity(opacity);
this._line.setOpacity(opacity);
}
redraw(): void {
const line2d = this._line2d;
const line2d = this._line;
const sourceTopic = this._sourceTopic;
const sourcePosition = sourceTopic.getPosition();
@ -132,10 +144,13 @@ class ConnectionLine {
}
// Add connector ...
this._positionateConnector(targetTopic);
this._positionLine(targetTopic);
// Update color ...
this.updateColor();
}
protected _positionateConnector(targetTopic: Topic): void {
protected _positionLine(targetTopic: Topic): void {
const targetPosition = targetTopic.getPosition();
const offset = TopicConfig.CONNECTOR_WIDTH / 2;
const targetTopicSize = targetTopic.getSize();
@ -161,16 +176,21 @@ class ConnectionLine {
}
setStroke(color: string, style: string, opacity: number) {
this._line2d.setStroke(null, null, color, opacity);
this._line.setStroke(null, null, color, opacity);
this._color = color;
}
getStrokeColor(): string {
return this._color;
}
addToWorkspace(workspace: Workspace) {
workspace.append(this._line2d);
this._line2d.moveToBack();
workspace.append(this._line);
this._line.moveToBack();
}
removeFromWorkspace(workspace: Workspace) {
workspace.removeChild(this._line2d);
workspace.removeChild(this._line);
}
getTargetTopic(): Topic {
@ -186,7 +206,7 @@ class ConnectionLine {
}
getLine(): Line {
return this._line2d;
return this._line;
}
getType(): string {
@ -194,14 +214,12 @@ class ConnectionLine {
}
moveToBack(): void {
this._line2d.moveToBack();
this._line.moveToBack();
}
moveToFront() {
this._line2d.moveToFront();
this._line.moveToFront();
}
static getStrokeColor = () => '#495879';
}
export default ConnectionLine;

View File

@ -439,56 +439,6 @@ class Designer extends Events {
this._actionDispatcher.addTopics([childModel], [parentTopicId]);
}
private _copyNodeProps(sourceModel: NodeModel, targetModel: NodeModel) {
// I don't copy the font size if the target is the source is the central topic.
if (sourceModel.getType() !== 'CentralTopic') {
const fontSize = sourceModel.getFontSize();
if (fontSize) {
targetModel.setFontSize(fontSize);
}
}
const fontFamily = sourceModel.getFontFamily();
if (fontFamily) {
targetModel.setFontFamily(fontFamily);
}
const fontColor = sourceModel.getFontColor();
if (fontColor) {
targetModel.setFontColor(fontColor);
}
const fontWeight = sourceModel.getFontWeight();
if (fontWeight) {
targetModel.setFontWeight(fontWeight);
}
const fontStyle = sourceModel.getFontStyle();
if (fontStyle) {
targetModel.setFontStyle(fontStyle);
}
const shape = sourceModel.getShapeType();
if (shape) {
targetModel.setShapeType(shape);
}
const borderColor = sourceModel.getBorderColor();
if (borderColor) {
targetModel.setBorderColor(borderColor);
}
const backgroundColor = sourceModel.getBackgroundColor();
if (backgroundColor) {
targetModel.setBackgroundColor(backgroundColor);
}
const connectType = sourceModel.getConnectionStyle();
if ($defined(connectType)) {
targetModel.setConnectionStyle(connectType!);
}
}
private _createChildModel(topic: Topic, mousePos: Point = null): NodeModel {
// Create a new node ...
const parentModel = topic.getModel();
@ -503,7 +453,7 @@ class Designer extends Events {
const { position } = result;
childModel.setPosition(position.x, position.y);
this._copyNodeProps(parentModel, childModel);
childModel.copy(parentModel);
return childModel;
}
@ -558,8 +508,7 @@ class Designer extends Events {
const order = topic.getOrder() + 1;
result.setOrder(order);
result.setPosition(10, 10); // Set a dummy position ...
this._copyNodeProps(model, result);
result.copy(model);
}
return result;
@ -884,6 +833,15 @@ class Designer extends Events {
}
}
changeConnectionColor(value: string): void {
const topicsIds = this.getModel()
.filterSelectedTopics()
.map((t) => t.getId());
if (topicsIds.length > 0) {
this._actionDispatcher.changeConnectionColorToTopic(topicsIds, value);
}
}
changeFontWeight(): void {
const topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {

View File

@ -56,15 +56,15 @@ class Relationship extends ConnectionLine {
const strokeColor = Relationship.getStrokeColor();
// Build line ..
this._line2d.setIsSrcControlPointCustom(false);
this._line2d.setIsDestControlPointCustom(false);
this._line2d.setCursor('pointer');
this._line2d.setStroke(1, 'solid', strokeColor);
this._line2d.setDashed(4, 2);
this._line2d.setTestId(`${model.getFromNode()}-${model.getToNode()}-relationship`);
this._line.setIsSrcControlPointCustom(false);
this._line.setIsDestControlPointCustom(false);
this._line.setCursor('pointer');
this._line.setStroke(1, 'solid', strokeColor);
this._line.setDashed(4, 2);
this._line.setTestId(`${model.getFromNode()}-${model.getToNode()}-relationship`);
// Build focus shape ...
this._focusShape = this._createLine(LineType.THIN_CURVED);
this._focusShape = this.createLine(LineType.THIN_CURVED);
this._focusShape.setStroke(8, 'solid', '#3f96ff');
this._focusShape.setIsSrcControlPointCustom(false);
this._focusShape.setIsDestControlPointCustom(false);
@ -122,7 +122,7 @@ class Relationship extends ConnectionLine {
}
private updatePositions() {
const line2d = this._line2d;
const line2d = this._line;
const sourceTopic = this._sourceTopic;
const sPos = sourceTopic.getPosition();
@ -132,7 +132,7 @@ class Relationship extends ConnectionLine {
tPos = Shape.workoutIncomingConnectionPoint(targetTopic, sPos);
}
this._line2d.setStroke(2);
this._line.setStroke(2);
let ctrlPoints: [Point, Point];
// Position line ...
@ -164,7 +164,7 @@ class Relationship extends ConnectionLine {
this.positionArrows();
// Add connector ...
this._positionateConnector(targetTopic);
this._positionLine(targetTopic);
// Poisition refresh shape ...
this.positionRefreshShape();
@ -173,7 +173,7 @@ class Relationship extends ConnectionLine {
redraw(): void {
this.updatePositions();
this._line2d.moveToFront();
this._line.moveToFront();
this._startArrow.moveToBack();
if (this._endArrow) {
this._endArrow.moveToBack();
@ -189,24 +189,24 @@ class Relationship extends ConnectionLine {
}
private positionArrows(): void {
const tpos = this._line2d.getTo();
const spos = this._line2d.getFrom();
const tpos = this._line.getTo();
const spos = this._line.getFrom();
this._startArrow.setFrom(spos.x, spos.y);
if (this._endArrow) {
this._endArrow.setFrom(tpos.x, tpos.y);
}
if (this._line2d.getType() === 'CurvedLine') {
const controlPoints = this._line2d.getControlPoints();
if (this._line.getType() === 'CurvedLine') {
const controlPoints = this._line.getControlPoints();
this._startArrow.setControlPoint(controlPoints[0]);
if (this._endArrow) {
this._endArrow.setControlPoint(controlPoints[1]);
}
} else {
this._startArrow.setControlPoint(this._line2d.getTo());
this._startArrow.setControlPoint(this._line.getTo());
if (this._endArrow) {
this._endArrow.setControlPoint(this._line2d.getFrom());
this._endArrow.setControlPoint(this._line.getFrom());
}
}
}
@ -218,9 +218,9 @@ class Relationship extends ConnectionLine {
workspace.append(this._controlPointsController);
if (workspace.isReadOnly()) {
this._line2d.setCursor('default');
this._line.setCursor('default');
} else {
this._line2d.addEvent('click', this._onFocusHandler);
this._line.addEvent('click', this._onFocusHandler);
this._focusShape.addEvent('click', this._onFocusHandler);
}
this._isInWorkspace = true;
@ -237,7 +237,7 @@ class Relationship extends ConnectionLine {
workspace.removeChild(this._focusShape);
workspace.removeChild(this._controlPointsController);
this._line2d.removeEvent('click', this._onFocusHandler);
this._line.removeEvent('click', this._onFocusHandler);
this._isInWorkspace = false;
workspace.removeChild(this._startArrow);
if (this._endArrow) {
@ -268,10 +268,10 @@ class Relationship extends ConnectionLine {
}
private positionRefreshShape(): void {
const sPos = this._line2d.getFrom();
const tPos = this._line2d.getTo();
const sPos = this._line.getFrom();
const tPos = this._line.getTo();
const ctrlPoints = this._line2d.getControlPoints();
const ctrlPoints = this._line.getControlPoints();
this._focusShape.setFrom(sPos.x, sPos.y);
this._focusShape.setTo(tPos.x, tPos.y);
@ -289,7 +289,7 @@ class Relationship extends ConnectionLine {
type = 'mousedown';
}
const line = this._line2d;
const line = this._line;
line.addEvent(type, listener);
}
@ -342,7 +342,7 @@ class Relationship extends ConnectionLine {
$assert($defined(x), 'x must be defined');
$assert($defined(y), 'y must be defined');
this._line2d.setFrom(x, y);
this._line.setFrom(x, y);
this._startArrow.setFrom(x, y);
}
@ -350,18 +350,18 @@ class Relationship extends ConnectionLine {
$assert($defined(x), 'x must be defined');
$assert($defined(y), 'y must be defined');
this._line2d.setTo(x, y);
this._line.setTo(x, y);
if (this._endArrow) this._endArrow.setFrom(x, y);
}
setSrcControlPoint(control: PositionType): void {
this._line2d.setSrcControlPoint(control);
this._line.setSrcControlPoint(control);
this._focusShape.setSrcControlPoint(control);
this._startArrow.setControlPoint(control);
}
setDestControlPoint(control: PositionType) {
this._line2d.setDestControlPoint(control);
this._line.setDestControlPoint(control);
this._focusShape.setSrcControlPoint(control);
if (this._showEndArrow) {
this._endArrow.setControlPoint(control);
@ -369,23 +369,23 @@ class Relationship extends ConnectionLine {
}
getControlPoints(): PositionType {
return this._line2d.getControlPoints();
return this._line.getControlPoints();
}
isSrcControlPointCustom(): boolean {
return this._line2d.isSrcControlPointCustom();
return this._line.isSrcControlPointCustom();
}
isDestControlPointCustom(): boolean {
return this._line2d.isDestControlPointCustom();
return this._line.isDestControlPointCustom();
}
setIsSrcControlPointCustom(isCustom: boolean) {
this._line2d.setIsSrcControlPointCustom(isCustom);
this._line.setIsSrcControlPointCustom(isCustom);
}
setIsDestControlPointCustom(isCustom: boolean) {
this._line2d.setIsDestControlPointCustom(isCustom);
this._line.setIsDestControlPointCustom(isCustom);
}
getId(): number {
@ -393,7 +393,7 @@ class Relationship extends ConnectionLine {
}
fireEvent(type: string, event): void {
const elem = this._line2d;
const elem = this._line;
elem.trigger(type, event);
}

View File

@ -31,7 +31,8 @@ class ShirinkConnector {
const ellipse = new Elipse(TopicConfig.INNER_RECT_ATTRIBUTES);
this._ellipse = ellipse;
ellipse.setFill('rgb(62,118,179)');
const fillColor = topic.getConnectionColor();
ellipse.setFill(fillColor);
ellipse.setSize(TopicConfig.CONNECTOR_WIDTH, TopicConfig.CONNECTOR_WIDTH);
ellipse.addEvent('click', (event: Event) => {

View File

@ -110,7 +110,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
topic.setFontStyle(style, true);
return result;
};
const command = new GenericFunctionCommand(commandFunc, topicsIds, null);
const command = new GenericFunctionCommand(commandFunc, topicsIds, undefined);
this.execute(command);
}
@ -225,9 +225,9 @@ class StandaloneActionDispatcher extends ActionDispatcher {
}
changeConnectionStyleToTopic(topicsIds: number[], lineType: LineType) {
const commandFunc = (topic: Topic, commandShapeType: LineType) => {
const commandFunc = (topic: Topic, type: LineType) => {
const result = topic.getConnectionStyle();
topic.setConnectionStyle(commandShapeType);
topic.setConnectionStyle(type);
return result;
};
@ -235,6 +235,17 @@ class StandaloneActionDispatcher extends ActionDispatcher {
this.execute(command);
}
changeConnectionColorToTopic(topicsIds: number[], value: string) {
const commandFunc = (topic: Topic, color: string) => {
const result: string = topic.getConnectionColor();
topic.setConnectionColor(color);
return result;
};
const command = new GenericFunctionCommand(commandFunc, topicsIds, value);
this.execute(command);
}
changeFontWeightToTopic(topicsIds: number[]) {
$assert(topicsIds, 'topicsIds can not be null');
@ -246,7 +257,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
return result;
};
const command = new GenericFunctionCommand(commandFunc, topicsIds, null);
const command = new GenericFunctionCommand(commandFunc, topicsIds, undefined);
this.execute(command);
}

View File

@ -114,11 +114,6 @@ abstract class Topic extends NodeGraph {
if ($defined(updateModel) && updateModel) {
model.setShapeType(type);
}
// If shape is line, reset background color to default.
if (type === 'line') {
const color = TopicStyle.defaultBackgroundColor(this);
this.setBackgroundColor(color);
}
const oldInnerShape = this.getInnerShape();
if (oldInnerShape != null) {
@ -163,11 +158,34 @@ abstract class Topic extends NodeGraph {
getConnectionStyle(): LineType {
const model = this.getModel();
let result = model.getConnectionStyle();
if (!result) {
let result: LineType | undefined = model.getConnectionStyle();
// Style is infered looking recursivelly on the parent nodes.
if (result === undefined) {
const parent = this.getParent();
if (parent) {
result = parent.getConnectionStyle();
} else {
result = TopicStyle.defaultConnectionType(this);
}
return result;
}
return result!;
}
getConnectionColor(): string {
const model = this.getModel();
let result: string | undefined = model.getConnectionColor();
// Style is infered looking recursivelly on the parent nodes.
if (!result) {
const parent = this.getParent();
if (parent) {
result = parent.getConnectionColor();
} else {
result = TopicStyle.defaultConnectionColor(this);
}
}
return result!;
}
private _removeInnerShape(): ElementClass {
@ -205,7 +223,7 @@ abstract class Topic extends NodeGraph {
$assert(attributes, 'attributes can not be null');
$assert(shapeType, 'shapeType can not be null');
let result;
let result: ElementClass;
if (shapeType === 'rectangle') {
result = new Rect(0, attributes);
} else if (shapeType === 'image') {
@ -229,22 +247,21 @@ abstract class Topic extends NodeGraph {
} else if (shapeType === 'rounded rectangle') {
result = new Rect(0.3, attributes);
} else if (shapeType === 'line') {
const stokeColor = this.getConnectionColor();
result = new Line({
strokeColor: '#495879',
strokeColor: stokeColor,
strokeWidth: 1,
});
const me = this;
result.setSize = function setSize(width: number, height: number) {
this.size = {
width,
height,
};
this.size = { width, height };
result.setFrom(0, height);
result.setTo(width, height);
// Lines will have the same color of the default connection lines...
const stokeColor = ConnectionLine.getStrokeColor();
result.setStroke(1, 'solid', stokeColor);
// // Lines will have the same color of the default connection lines...
const color = me.getConnectionColor();
result.setStroke(1, 'solid', color);
};
result.getSize = function getSize() {
@ -522,7 +539,7 @@ abstract class Topic extends NodeGraph {
if ($defined(updateModel) && updateModel) {
const model = this.getModel();
model.setText(text);
model.setText(text || undefined);
}
}
@ -552,13 +569,29 @@ abstract class Topic extends NodeGraph {
model.setConnectionStyle(type);
// Needs to change change all the lines types. Outgoing are part of the children.
this.getChildren().map((topic: Topic) => topic.redraw());
this.getChildren().forEach((topic: Topic) => topic.redraw());
// If chidren nodes does not children, set the connection style too. We don't want to have cascade changes on all the branches.
model
.getChildren()
.filter((c) => c.getChildren().length === 0)
.forEach((c) => c.setConnectionStyle(type));
// If connection of the childen matches, just reset the style in the model.
this.getChildren().forEach((topic: Topic) => {
if (topic.getModel().getConnectionStyle() === type) {
topic.getModel().setConnectionStyle(undefined);
}
});
}
setConnectionColor(value: string): void {
const model = this.getModel();
model.setConnectionColor(value);
// Needs to change change all the lines color. Outgoing are part of the children.
this.getChildren().forEach((topic: Topic) => topic.redraw());
// If connection of the childen matches, just reset the style in the model.
this.getChildren().forEach((topic: Topic) => {
if (topic.getModel().getConnectionColor() === value) {
topic.getModel().setConnectionColor(undefined);
}
});
}
private _setBackgroundColor(color: string, updateModel: boolean) {
@ -1247,9 +1280,11 @@ abstract class Topic extends NodeGraph {
let result = false;
if (this._isInWorkspace) {
// Adjust connection line if there is a change in the parent...
if (this._outgoingLine) {
// Has the style change ?
const connStyleChanged =
this._outgoingLine?.getLineType() !== this.getParent()?.getConnectionStyle();
if (this._outgoingLine && connStyleChanged) {
this._outgoingLine.getLineType() !== this.getParent()!.getConnectionStyle();
if (connStyleChanged) {
// Todo: Review static reference ...
const workspace = designer.getWorkSpace();
this._outgoingLine.removeFromWorkspace(workspace);
@ -1259,8 +1294,20 @@ abstract class Topic extends NodeGraph {
this._outgoingLine.setVisibility(this.isVisible());
workspace.append(this._outgoingLine);
// Update all the children...
this.getChildren().forEach((t) => t.redraw());
result = true;
}
// Has the color changed ?
const color = this._outgoingLine.getStrokeColor();
const connColorChanged = color !== this.getParent()!.getConnectionColor();
if (connColorChanged) {
this._outgoingLine.redraw();
this._connector.setFill(color);
this.getChildren().forEach((t) => t.redraw());
}
}
}
return result;
}

View File

@ -28,10 +28,12 @@ type FontStlye = {
weight: string;
color: string;
};
type TopicStyleType = {
borderColor: string;
backgroundColor: string;
connectionStyle: LineType;
connectionColor: string;
fontStyle: FontStlye;
msgKey: string;
shapeType: TopicShapeType;
@ -49,6 +51,7 @@ const TopicDefaultStyles = {
color: '#ffffff',
},
connectionStyle: LineType.THICK_CURVED,
connectionColor: '#495879',
msgKey: 'CENTRAL_TOPIC',
shapeType: 'rounded rectangle' as TopicShapeType,
},
@ -63,6 +66,7 @@ const TopicDefaultStyles = {
color: 'rgb(82,92,97)',
},
connectionStyle: LineType.THICK_CURVED,
connectionColor: '#495879',
msgKey: 'MAIN_TOPIC',
shapeType: 'line' as TopicShapeType,
},
@ -76,7 +80,8 @@ const TopicDefaultStyles = {
weight: 'normal',
color: 'rgb(82,92,97)',
},
connectionStyle: LineType.THIN_CURVED,
connectionStyle: LineType.THICK_CURVED,
connectionColor: '#495879',
msgKey: 'SUB_TOPIC',
shapeType: 'line' as TopicShapeType,
},
@ -93,6 +98,7 @@ const TopicDefaultStyles = {
},
msgKey: 'ISOLATED_TOPIC',
connectionStyle: LineType.THIN_CURVED,
connectionColor: '#495879',
shapeType: 'line' as TopicShapeType,
},
};
@ -147,6 +153,10 @@ class TopicStyle {
static defaultConnectionType(topic: Topic): LineType {
return this._getStyles(topic).connectionStyle;
}
static defaultConnectionColor(topic: Topic): string {
return this._getStyles(topic).connectionColor;
}
}
export default TopicStyle;

View File

@ -20,7 +20,7 @@ import Command from '../Command';
import CommandContext from '../CommandContext';
import Topic from '../Topic';
type CommandTypes = string | object | boolean | number | null;
type CommandTypes = string | object | boolean | number | undefined;
class GenericFunctionCommand extends Command {
private _value: CommandTypes;

View File

@ -251,7 +251,7 @@ class FreemindExporter extends Exporter {
const fontFamily: string = mindmapTopic.getFontFamily();
const fontSize: number = mindmapTopic.getFontSize();
const fontColor: string = mindmapTopic.getFontColor();
const fontWeigth: string | number | boolean = mindmapTopic.getFontWeight();
const fontWeigth: string | number | boolean | undefined = mindmapTopic.getFontWeight();
const fontStyle: string = mindmapTopic.getFontStyle();
if (fontFamily || fontSize || fontColor || fontWeigth || fontStyle) {

View File

@ -70,7 +70,7 @@ abstract class INodeModel {
this.putProperty('type', type);
}
setText(text: string | null): void {
setText(text: string | undefined): void {
this.putProperty('text', text);
}
@ -221,14 +221,22 @@ abstract class INodeModel {
this.putProperty('shrunken', value);
}
setConnectionStyle(type: LineType): void {
setConnectionStyle(type: LineType | undefined): void {
this.putProperty('connectionStyle', type);
}
getConnectionStyle(): LineType | null {
getConnectionStyle(): LineType | undefined {
return this.getProperty('connectionStyle') as LineType;
}
setConnectionColor(value: string | undefined): void {
this.putProperty('connectionColor', value);
}
getConnectionColor(): string | undefined {
return this.getProperty('connectionColor') as string;
}
isNodeModel(): boolean {
return true;
}
@ -297,9 +305,9 @@ abstract class INodeModel {
abstract getPropertiesKeys(): string[];
abstract getProperty(key: string): number | string | boolean;
abstract getProperty(key: string): number | string | boolean | undefined;
abstract putProperty(key: string, value: number | string | boolean | null): void;
abstract putProperty(key: string, value: number | string | boolean | undefined): void;
abstract setParent(parent: INodeModel): void;

View File

@ -108,7 +108,7 @@ class NodeModel extends INodeModel {
* @param value
* @throws will throw an error if key is null or undefined
*/
putProperty(key: string, value: string | number | boolean) {
putProperty(key: string, value: string | number | boolean): void {
$defined(key, 'key can not be null');
this._properties[key] = value;
}
@ -117,7 +117,7 @@ class NodeModel extends INodeModel {
return this._properties;
}
getProperty(key: string): number | string | boolean {
getProperty(key: string): number | string | boolean | undefined {
$defined(key, 'key can not be null');
return this._properties[key];
}
@ -135,6 +135,61 @@ class NodeModel extends INodeModel {
return result;
}
copy(value: NodeModel) {
// I don't copy the font size if the target is the source is the central topic.
if (value.getType() !== 'CentralTopic') {
const fontSize = value.getFontSize();
if (fontSize) {
this.setFontSize(fontSize);
}
}
const fontFamily = value.getFontFamily();
if (fontFamily) {
this.setFontFamily(fontFamily);
}
const fontColor = value.getFontColor();
if (fontColor) {
this.setFontColor(fontColor);
}
const fontWeight = value.getFontWeight();
if (fontWeight) {
this.setFontWeight(fontWeight);
}
const fontStyle = value.getFontStyle();
if (fontStyle) {
this.setFontStyle(fontStyle);
}
const shape = value.getShapeType();
if (shape) {
this.setShapeType(shape);
}
const borderColor = value.getBorderColor();
if (borderColor) {
this.setBorderColor(borderColor);
}
const backgroundColor = value.getBackgroundColor();
if (backgroundColor) {
this.setBackgroundColor(backgroundColor);
}
const connectType = value.getConnectionStyle();
if ($defined(connectType)) {
this.setConnectionStyle(connectType!);
}
const connectColor = value.getConnectionColor();
if ($defined(connectColor)) {
this.setConnectionColor(connectColor!);
}
}
deepCopy(): NodeModel {
const result = new NodeModel(this.getType(), this._mindmap);
result._children = this._children.map((node) => {

View File

@ -148,7 +148,7 @@ class XMLSerializerTango implements XMLMindmapSerializer {
}
const brColor = topic.getBorderColor();
if ($defined(brColor)) {
if (brColor) {
parentTopic.setAttribute('brColor', brColor);
}
@ -157,6 +157,11 @@ class XMLSerializerTango implements XMLMindmapSerializer {
parentTopic.setAttribute('connStyle', `${connectionStyle}`);
}
const connectionColor = topic.getConnectionColor();
if (connectionColor) {
parentTopic.setAttribute('connColor', connectionColor);
}
const metadata = topic.getMetadata();
if ($defined(metadata)) {
parentTopic.setAttribute('metadata', metadata);
@ -351,6 +356,11 @@ class XMLSerializerTango implements XMLMindmapSerializer {
topic.setConnectionStyle(lineType);
}
const connColor = domElem.getAttribute('connColor');
if ($defined(connColor) && connColor) {
topic.setConnectionColor(connColor);
}
const borderColor = domElem.getAttribute('brColor');
if (borderColor) {
topic.setBorderColor(borderColor);

View File

@ -24,12 +24,11 @@ class CurvedLinePeer extends ElementPeer {
const svgElement = window.document.createElementNS(ElementPeer.svgNamespace, 'path');
super(svgElement);
this._style = { fill: '#495879' };
this._updateStyle();
this._customControlPoint_1 = false;
this._customControlPoint_2 = false;
this._control1 = new Point(0, 0);
this._control2 = new Point(0, 0);
this._width = 1;
this.setWidth(1);
}
setSrcControlPoint(control) {