Add support for new theme

This commit is contained in:
Paulo Gustavo Veiga 2023-02-28 21:54:30 -03:00
parent dc1e9c6549
commit e64c72d719
13 changed files with 123 additions and 137 deletions

View File

@ -25,7 +25,8 @@
"cypress": "^12.3.0", "cypress": "^12.3.0",
"cypress-image-snapshot": "^4.0.1", "cypress-image-snapshot": "^4.0.1",
"jest-transform-stub": "^2.0.0", "jest-transform-stub": "^2.0.0",
"react": "^18.2.0" "react": "^18.2.0",
"start-server-and-test": "^2.0.0"
}, },
"dependencies": { "dependencies": {
"@wisemapping/mindplot": "^5.0.20", "@wisemapping/mindplot": "^5.0.20",

View File

@ -224,7 +224,7 @@ class NodePropertyBuilder {
if (!this.topicShapeModel) if (!this.topicShapeModel)
this.topicShapeModel = { this.topicShapeModel = {
getValue: () => this.uniqueOrNull((node) => node.getShapeType()) as TopicShapeType, getValue: () => this.uniqueOrNull((node) => node.getShapeType()) as TopicShapeType,
setValue: (value: TopicShapeType) => this.designer.changeTopicShape(value), setValue: (value: TopicShapeType) => this.designer.changeShapeType(value),
}; };
return this.topicShapeModel; return this.topicShapeModel;
} }

View File

@ -43,8 +43,8 @@ class CentralTopic extends Topic {
super.setCursor(type === 'move' ? 'default' : type); super.setCursor(type === 'move' ? 'default' : type);
} }
updateTopicShape(): void { updateTopicShape(): boolean {
// Overwite behaviour ... return true;
} }
updatePositionOnChangeSize(): void { updatePositionOnChangeSize(): void {

View File

@ -898,7 +898,7 @@ class Designer extends EventDispispatcher<DesignerEventType> {
} }
} }
changeTopicShape(shape: TopicShapeType): void { changeShapeType(shape: TopicShapeType): void {
const validateFunc = (topic: Topic) => const validateFunc = (topic: Topic) =>
!(topic.getType() === 'CentralTopic' && (shape === 'line' || shape === 'none')); !(topic.getType() === 'CentralTopic' && (shape === 'line' || shape === 'none'));

View File

@ -41,6 +41,7 @@ class DesignerActionRunner {
$assert(command, 'command can not be null'); $assert(command, 'command can not be null');
command.execute(this._context); command.execute(this._context);
this._undoManager.enqueue(command); this._undoManager.enqueue(command);
this.fireChangeEvent(); this.fireChangeEvent();
LayoutEventBus.fireEvent('forceLayout'); LayoutEventBus.fireEvent('forceLayout');
} }

View File

@ -65,10 +65,6 @@ class MainTopic extends Topic {
return group; return group;
} }
updateTopicShape() {
this.redrawShapeType();
}
disconnect(canvas: Canvas) { disconnect(canvas: Canvas) {
super.disconnect(canvas); super.disconnect(canvas);

View File

@ -199,12 +199,10 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
changeShapeTypeToTopic(topicsIds: number[], shapeType: TopicShapeType) { changeShapeTypeToTopic(topicsIds: number[], shapeType: TopicShapeType) {
$assert(topicsIds, 'topicsIds can not be null');
$assert(shapeType, 'shapeType can not be null');
const commandFunc = (topic: Topic, commandShapeType: TopicShapeType) => { const commandFunc = (topic: Topic, commandShapeType: TopicShapeType) => {
const result = topic.getShapeType(); const result = topic.getShapeType();
topic.setShapeType(commandShapeType); topic.setShapeType(commandShapeType);
return result; return result;
}; };

View File

@ -117,34 +117,38 @@ abstract class Topic extends NodeGraph {
return this._parent; return this._parent;
} }
protected redrawShapeType() { updateTopicShape(): boolean {
this.removeInnerShape(); const result = this.getInnerShape().getShapeType() !== this.getShapeType();
if (result) {
this.removeInnerShape();
// Create a new one ... // Create a new one ...
const innerShape = this.getInnerShape(); const innerShape = this.getInnerShape();
// Update figure size ... // Update figure size ...
const size = this.getSize(); const size = this.getSize();
this.setSize(size, true); this.setSize(size, true);
const group = this.get2DElement(); const group = this.get2DElement();
innerShape.appendTo(group); innerShape.appendTo(group);
// Move text to the front ... // Move text to the front ...
const text = this.getOrBuildTextShape(); const text = this.getOrBuildTextShape();
text.moveToFront(); text.moveToFront();
// Move iconGroup to front ... // Move iconGroup to front ...
const iconGroup = this.getIconGroup(); const iconGroup = this.getIconGroup();
if (iconGroup) { if (iconGroup) {
iconGroup.moveToFront(); iconGroup.moveToFront();
} }
// Move connector to front // Move connector to front
const connector = this.getShrinkConnector(); const connector = this.getShrinkConnector();
if (connector) { if (connector) {
connector.moveToFront(); connector.moveToFront();
}
} }
return result;
} }
getShapeType(): TopicShapeType { getShapeType(): TopicShapeType {
@ -709,7 +713,7 @@ abstract class Topic extends NodeGraph {
this.get2DElement().setPosition(cx, cy); this.get2DElement().setPosition(cx, cy);
// Update connection lines ... // Update connection lines ...
this._updateConnectionLines(); this.updateConnection();
// Check object state. // Check object state.
this.invariant(); this.invariant();
@ -735,21 +739,6 @@ abstract class Topic extends NodeGraph {
return result; return result;
} }
private _updateConnectionLines(): void {
// Update this to parent line ...
const outgoingLine = this.getOutgoingLine();
if (outgoingLine) {
outgoingLine.redraw();
}
// Update all the incoming lines ...
const incomingLines = this.getIncomingLines();
incomingLines.forEach((line) => line.redraw());
// Update relationship lines
this._relationships.forEach((r) => r.redraw());
}
setBranchVisibility(value: boolean): void { setBranchVisibility(value: boolean): void {
let current: Topic = this; let current: Topic = this;
let parent: Topic | null = this; let parent: Topic | null = this;
@ -948,7 +937,6 @@ abstract class Topic extends NodeGraph {
const model = this.getModel(); const model = this.getModel();
model.setOrder(value); model.setOrder(value);
// In case of drag a node, color change based on the order ...
this.redraw(); this.redraw();
} }
@ -964,14 +952,10 @@ abstract class Topic extends NodeGraph {
// Create a connection line ... // Create a connection line ...
const outgoingLine = this.createConnectionLine(targetTopic); const outgoingLine = this.createConnectionLine(targetTopic);
// outgoingLine.setVisibility(false);
this._outgoingLine = outgoingLine; this._outgoingLine = outgoingLine;
canvas.append(outgoingLine); canvas.append(outgoingLine);
// Update figure is necessary.
this.updateTopicShape(targetTopic);
// Display connection node... // Display connection node...
const connector = targetTopic.getShrinkConnector(); const connector = targetTopic.getShrinkConnector();
if (connector) { if (connector) {
@ -984,6 +968,10 @@ abstract class Topic extends NodeGraph {
parentNode: targetTopic.getModel(), parentNode: targetTopic.getModel(),
childNode: this.getModel(), childNode: this.getModel(),
}); });
// Hack for the case of first node created, it needs to review the positioning problem.
LayoutEventBus.fireEvent('forceLayout');
this.redraw();
} }
} }
@ -992,8 +980,6 @@ abstract class Topic extends NodeGraph {
return new ConnectionLine(this, targetTopic, type); return new ConnectionLine(this, targetTopic, type);
} }
abstract updateTopicShape(targetTopic: Topic): void;
append(child: Topic): void { append(child: Topic): void {
const children = this.getChildren(); const children = this.getChildren();
children.push(child); children.push(child);
@ -1060,17 +1046,15 @@ abstract class Topic extends NodeGraph {
return result; return result;
} }
private redrawConnection(): boolean { private updateConnection(): boolean {
let result = false; let result = false;
if (this._isInWorkspace) { if (this._isInWorkspace) {
// Adjust connection line if there is a change in the parent...
if (this._outgoingLine) { if (this._outgoingLine) {
// Has the style change ? // Has the style change ?
const connStyleChanged = const connStyleChanged =
this._outgoingLine.getLineType() !== this.getParent()!.getConnectionStyle(); this._outgoingLine.getLineType() !== this.getParent()!.getConnectionStyle();
if (connStyleChanged) { if (connStyleChanged) {
// Todo: Review static reference ...
const workspace = designer.getWorkSpace(); const workspace = designer.getWorkSpace();
this._outgoingLine.removeFromWorkspace(workspace); this._outgoingLine.removeFromWorkspace(workspace);
@ -1079,11 +1063,18 @@ abstract class Topic extends NodeGraph {
this._outgoingLine.setVisibility(this.isVisible()); this._outgoingLine.setVisibility(this.isVisible());
workspace.append(this._outgoingLine); workspace.append(this._outgoingLine);
const incomingLines = this.getIncomingLines();
incomingLines.forEach((line) => line.redraw());
result = true; result = true;
} }
// Force the repaint in case that the main topic color has changed.
const borderColor = this.getBorderColor();
this._connector!.setColor(borderColor);
this._outgoingLine.redraw(); this._outgoingLine.redraw();
result = true;
} }
} }
return result; return result;
@ -1094,11 +1085,8 @@ abstract class Topic extends NodeGraph {
const theme = ThemeFactory.create(this.getModel()); const theme = ThemeFactory.create(this.getModel());
const textShape = this.getOrBuildTextShape(); const textShape = this.getOrBuildTextShape();
// Needs to update inner shape ... // Update shape ...
const shapeType = this.getShapeType(); const shapeChanged = this.updateTopicShape();
if (shapeType !== this._innerShape?.getShapeType()) {
this.redrawShapeType();
}
// Update font ... // Update font ...
const fontColor = this.getFontColor(); const fontColor = this.getFontColor();
@ -1145,32 +1133,27 @@ abstract class Topic extends NodeGraph {
const topicWith = iconGroupWith + 2 * textIconSpacing + textWidth + padding * 2; const topicWith = iconGroupWith + 2 * textIconSpacing + textWidth + padding * 2;
// Update connections ... // Update connections ...
const changed = this.redrawConnection(); const connectionChanged = this.updateConnection();
this.setSize({ width: topicWith, height: topicHeight }, changed); this.setSize({ width: topicWith, height: topicHeight }, connectionChanged);
// Adjust all topic elements positions ... // Adjust all topic elements positions ...
const yPosition = (topicHeight - textHeight) / 2; const yPosition = (topicHeight - textHeight) / 2;
iconGroup.setPosition(padding, yPosition - yPosition / 4); iconGroup.setPosition(padding, yPosition - yPosition / 4);
textShape.setPosition(padding + iconGroupWith + textIconSpacing, yPosition); textShape.setPosition(padding + iconGroupWith + textIconSpacing, yPosition);
// Update relationship lines
this._relationships.forEach((r) => r.redraw());
// Update topic color ... // Update topic color ...
const innerShape = this.getInnerShape();
const borderColor = this.getBorderColor(); const borderColor = this.getBorderColor();
this.getInnerShape().setStroke(null, 'solid', borderColor); innerShape.setStroke(null, 'solid', borderColor);
const bgColor = this.getBackgroundColor(); const bgColor = this.getBackgroundColor();
this.getInnerShape().setFill(bgColor); innerShape.setFill(bgColor);
// Force the repaint in case that the main topic color has changed. if (redrawChildren || shapeChanged || connectionChanged) {
if (this.getParent()) { this.getChildren().forEach((t) => t.redraw(true));
this._connector!.setColor(borderColor);
if (this.getParent()?.isCentralTopic()) {
this._outgoingLine?.redraw();
}
}
if (redrawChildren) {
this.getChildren().forEach((t) => t.redraw(redrawChildren));
} }
} }
} }

View File

@ -199,7 +199,6 @@ class LayoutManager extends EventDispispatcher<LayoutEventType> {
node.resetPositionState(); node.resetPositionState();
node.resetOrderState(); node.resetOrderState();
node.resetFreeState();
this._events.push(event); this._events.push(event);
} }
this._collectChanges(this._treeSet.getChildren(node)); this._collectChanges(this._treeSet.getChildren(node));

View File

@ -55,43 +55,30 @@ class Node {
return this._id; return this._id;
} }
/** */
setFree(value) {
this._setProperty('free', value);
}
/** */
isFree() {
return this._getProperty('free');
}
/** */
hasFreeChanged() {
return this._isPropertyChanged('free');
}
/** */ /** */
hasFreeDisplacementChanged() { hasFreeDisplacementChanged() {
return this._isPropertyChanged('freeDisplacement'); return this.isPropertyChanged('freeDisplacement');
} }
/** */ /** */
setShrunken(value: boolean) { setShrunken(value: boolean) {
this._setProperty('shrink', value); this.setProperty('shrink', value);
} }
/** */ /** */
areChildrenShrunken() { areChildrenShrunken() {
return this._getProperty('shrink'); return this.getProperty('shrink');
} }
/** */
setOrder(order: number) { setOrder(order: number) {
$assert( $assert(
typeof order === 'number' && Number.isFinite(order), typeof order === 'number' && Number.isFinite(order),
`Order can not be null. Value:${order}`, `Order can not be null. Value:${order}`,
); );
this._setProperty('order', order);
if (this.getOrder() !== order) {
this.setProperty('order', order);
}
} }
/** */ /** */
@ -118,68 +105,75 @@ class Node {
} }
} }
/** */ getOrder(): number {
getOrder() { return this.getProperty('order') as number;
return this._getProperty('order');
} }
/** */ /** */
hasOrderChanged() { hasOrderChanged() {
return this._isPropertyChanged('order'); return this.isPropertyChanged('order');
} }
/** */ /** */
hasPositionChanged() { hasPositionChanged() {
return this._isPropertyChanged('position'); return this.isPropertyChanged('position');
} }
/** */
hasSizeChanged(): boolean { hasSizeChanged(): boolean {
return this._isPropertyChanged('size'); return this.isPropertyChanged('size');
} }
/** */
getPosition(): PositionType { getPosition(): PositionType {
return this._getProperty('position'); return this.getProperty('position') as PositionType;
} }
/** */ /** */
setSize(size: SizeType) { setSize(size: SizeType): void {
this._setProperty('size', { ...size }); const currentSize = this.getSize();
if (
!currentSize ||
(currentSize &&
(Math.abs(currentSize.height - size.height) > 0.5 ||
Math.abs(currentSize.width - size.width) > 0.5))
) {
this.setProperty('size', { ...size });
}
} }
/** */ /** */
getSize(): SizeType { getSize(): SizeType {
return this._getProperty('size'); return this.getProperty('size') as SizeType;
} }
setFreeDisplacement(displacement: PositionType) { setFreeDisplacement(displacement: PositionType): void {
const oldDisplacement = this.getFreeDisplacement(); const oldDisplacement = this.getFreeDisplacement();
const newDisplacement = { const newDisplacement = {
x: oldDisplacement.x + displacement.x, x: oldDisplacement.x + displacement.x,
y: oldDisplacement.y + displacement.y, y: oldDisplacement.y + displacement.y,
}; };
this._setProperty('freeDisplacement', { ...newDisplacement }); this.setProperty('freeDisplacement', { ...newDisplacement });
} }
/** */ /** */
resetFreeDisplacement() { getFreeDisplacement(): PositionType {
this._setProperty('freeDisplacement', { x: 0, y: 0 }); const freeDisplacement = this.getProperty('freeDisplacement') as PositionType;
}
/** */
getFreeDisplacement() {
const freeDisplacement = this._getProperty('freeDisplacement');
return freeDisplacement || { x: 0, y: 0 }; return freeDisplacement || { x: 0, y: 0 };
} }
setPosition(position: PositionType) { setPosition(position: PositionType): void {
// This is a performance improvement to avoid movements that really could be avoided. // This is a performance improvement to avoid movements that really could be avoided.
this._setProperty('position', position); const currentPos = this.getPosition();
if (
!currentPos ||
(currentPos &&
(Math.abs(currentPos.x - position.x) > 0.5 || Math.abs(currentPos.y - position.y) > 0.5))
) {
this.setProperty('position', { ...position });
}
} }
_setProperty(key: string, value) { setProperty(key: string, value) {
let prop = this._properties[key]; let prop = this._properties[key];
if (!prop) { if (!prop) {
prop = { prop = {
@ -198,12 +192,12 @@ class Node {
this._properties[key] = prop; this._properties[key] = prop;
} }
_getProperty(key: string) { private getProperty(key: string): null | number | PositionType | SizeType {
const prop = this._properties[key]; const prop = this._properties[key];
return $defined(prop) ? prop.value : null; return $defined(prop) ? prop.value : null;
} }
_isPropertyChanged(key) { isPropertyChanged(key: string) {
const prop = this._properties[key]; const prop = this._properties[key];
return prop ? prop.hasChanged : false; return prop ? prop.hasChanged : false;
} }

View File

@ -60,10 +60,6 @@ class OriginalLayout {
throw new Error('Node already disconnected'); throw new Error('Node already disconnected');
} }
// Make it fixed
node.setFree(false);
node.resetFreeDisplacement();
// Remove from children list. // Remove from children list.
const sorter = parent.getSorter(); const sorter = parent.getSorter();
sorter.detach(this._treeSet, node); sorter.detach(this._treeSet, node);
@ -174,9 +170,6 @@ class OriginalLayout {
private fixOverlapping(node: Node, heightById: Map<number, number>): void { private fixOverlapping(node: Node, heightById: Map<number, number>): void {
const children = this._treeSet.getChildren(node); const children = this._treeSet.getChildren(node);
if (node.isFree()) {
this._shiftBranches(node, heightById);
}
children.forEach((child) => { children.forEach((child) => {
this.fixOverlapping(child, heightById); this.fixOverlapping(child, heightById);
}); });
@ -196,7 +189,7 @@ class OriginalLayout {
OriginalLayout._branchesOverlap(shiftedBranch, sibling, heightById), OriginalLayout._branchesOverlap(shiftedBranch, sibling, heightById),
); );
/* eslint-enable */ /* eslint-enable */
if (!sibling.isFree() || overlappingOccurs) { if (overlappingOccurs) {
const sAmount = node.getFreeDisplacement().y; const sAmount = node.getFreeDisplacement().y;
this._treeSet.shiftBranchPosition(sibling, 0, sAmount); this._treeSet.shiftBranchPosition(sibling, 0, sAmount);
shiftedBranches.push(sibling); shiftedBranches.push(sibling);

View File

@ -288,7 +288,7 @@ class RootedTreeSet {
if (this._rootNodes.includes(node)) { if (this._rootNodes.includes(node)) {
fillColor = '#000'; fillColor = '#000';
} else { } else {
fillColor = node.isFree() ? '#abc' : '#c00'; fillColor = '#c00';
} }
rect.attr('fill', fillColor); rect.attr('fill', fillColor);

View File

@ -6421,6 +6421,7 @@ __metadata:
react: ^18.2.0 react: ^18.2.0
react-color: ^2.19.3 react-color: ^2.19.3
react-loader-spinner: ^5.3.4 react-loader-spinner: ^5.3.4
start-server-and-test: ^2.0.0
peerDependencies: peerDependencies:
"@emotion/react": ^11.10.5 "@emotion/react": ^11.10.5
"@emotion/styled": ^11.10.5 "@emotion/styled": ^11.10.5
@ -20604,6 +20605,26 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"start-server-and-test@npm:^2.0.0":
version: 2.0.0
resolution: "start-server-and-test@npm:2.0.0"
dependencies:
arg: ^5.0.2
bluebird: 3.7.2
check-more-types: 2.24.0
debug: 4.3.4
execa: 5.1.1
lazy-ass: 1.6.0
ps-tree: 1.2.0
wait-on: 7.0.1
bin:
server-test: src/bin/start.js
start-server-and-test: src/bin/start.js
start-test: src/bin/start.js
checksum: 8788e59ad78275332c78325a804504ac558f06a112d47cb5bc3d012d2bda46add72c863cae2357836fe245ee4e22e2fec0b6d47dbdf5e0f0f5cfd1a57544d100
languageName: node
linkType: hard
"state-toggle@npm:^1.0.0": "state-toggle@npm:^1.0.0":
version: 1.0.3 version: 1.0.3
resolution: "state-toggle@npm:1.0.3" resolution: "state-toggle@npm:1.0.3"