Introduce Theme framework.
@ -48,7 +48,7 @@ describe('Topic Shape Suite', () => {
|
||||
.invoke('attr', 'rx')
|
||||
.then(parseInt)
|
||||
.should('be.a', 'number')
|
||||
.should('be.lt', 5);
|
||||
.should('be.lte', 8);
|
||||
|
||||
cy.focusTopicByText('Mind Mapping');
|
||||
cy.matchImageSnapshot('changeToRoundedRectangle');
|
||||
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 205 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 153 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 144 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
@ -96,10 +96,7 @@ class ConnectionLine {
|
||||
|
||||
private updateColor(): string {
|
||||
// In case that the main topic has changed the color, overwrite the main topic definiton.
|
||||
let color = this._targetTopic.getConnectionColor();
|
||||
if (this._targetTopic.isCentralTopic()) {
|
||||
color = this._sourceTopic.getModel().getConnectionColor() || color;
|
||||
}
|
||||
const color = this._sourceTopic.getConnectionColor();
|
||||
|
||||
this._color = color;
|
||||
switch (this._type) {
|
||||
|
@ -523,8 +523,6 @@ class Designer extends Events {
|
||||
const { position } = result;
|
||||
childModel.setPosition(position.x, position.y);
|
||||
|
||||
childModel.copy(parentModel);
|
||||
|
||||
return childModel;
|
||||
}
|
||||
|
||||
@ -554,7 +552,7 @@ class Designer extends Events {
|
||||
// Hack: if parent is central topic, add node below not on opposite side.
|
||||
// This should be done in the layout
|
||||
if (parentTopic.getType() === 'CentralTopic') {
|
||||
siblingModel.setOrder(topic.getOrder() + 2);
|
||||
siblingModel.setOrder(topic.getOrder()! + 2);
|
||||
}
|
||||
|
||||
const parentTopicId = parentTopic.getId();
|
||||
@ -575,10 +573,9 @@ class Designer extends Events {
|
||||
result = mindmap.createNode();
|
||||
|
||||
// Create a new node ...
|
||||
const order = topic.getOrder() + 1;
|
||||
const order = topic.getOrder()! + 1;
|
||||
result.setOrder(order);
|
||||
result.setPosition(10, 10); // Set a dummy position ...
|
||||
result.copy(model);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -671,7 +668,7 @@ class Designer extends Events {
|
||||
nodeModelToTopic(nodeModel: NodeModel): Topic {
|
||||
$assert(nodeModel, 'Node model can not be null');
|
||||
let children = nodeModel.getChildren().slice();
|
||||
children = children.sort((a, b) => a.getOrder() - b.getOrder());
|
||||
children = children.sort((a, b) => a.getOrder()! - b.getOrder()!);
|
||||
|
||||
const result = this._buildNodeGraph(nodeModel, this.isReadOnly());
|
||||
result.setVisibility(false);
|
||||
|
@ -26,7 +26,8 @@ import PositionType from './PositionType';
|
||||
|
||||
class MainTopic extends Topic {
|
||||
buildDragShape(): ElementClass<ElementPeer> {
|
||||
const innerShape = this._buildShape(this.getShapeType());
|
||||
const shapeType = this.getShapeType();
|
||||
const innerShape = this._buildShape(shapeType);
|
||||
const size = this.getSize();
|
||||
innerShape.setSize(size.width, size.height);
|
||||
innerShape.setPosition(0, 0);
|
||||
@ -50,27 +51,21 @@ class MainTopic extends Topic {
|
||||
const group = new Group(groupAttributes);
|
||||
group.append(innerShape);
|
||||
|
||||
// Add Text ...
|
||||
if (this.getShapeType() !== 'image') {
|
||||
const textShape = this._buildTextShape(true);
|
||||
const text = this.getText();
|
||||
textShape.setText(text);
|
||||
textShape.setOpacity(0.5);
|
||||
const textShape = this._buildTextShape(true);
|
||||
const text = this.getText();
|
||||
textShape.setText(text);
|
||||
textShape.setOpacity(0.5);
|
||||
|
||||
// Copy text position of the topic element ...
|
||||
const textPosition = this.getOrBuildTextShape().getPosition();
|
||||
textShape.setPosition(textPosition.x, textPosition.y);
|
||||
// Copy text position of the topic element ...
|
||||
const textPosition = this.getOrBuildTextShape().getPosition();
|
||||
textShape.setPosition(textPosition.x, textPosition.y);
|
||||
|
||||
group.append(textShape);
|
||||
}
|
||||
group.append(textShape);
|
||||
return group;
|
||||
}
|
||||
|
||||
updateTopicShape(targetTopic: Topic) {
|
||||
if (!targetTopic.isCentralTopic()) {
|
||||
// Get the real shape type ...
|
||||
this.redrawShapeType();
|
||||
}
|
||||
updateTopicShape(_targetTopic: Topic) {
|
||||
this.redrawShapeType();
|
||||
}
|
||||
|
||||
disconnect(workspace: Canvas) {
|
||||
|
@ -27,7 +27,7 @@ import { $notify } from './widget/ToolbarNotifier';
|
||||
import { $msg } from './Messages';
|
||||
import DesignerKeyboard from './DesignerKeyboard';
|
||||
import LocalStorageManager from './LocalStorageManager';
|
||||
import TopicStyle from './TopicStyle';
|
||||
import ThemeFactory from './theme/ThemeFactory';
|
||||
|
||||
/**
|
||||
* WebComponent implementation for minplot designer.
|
||||
@ -54,7 +54,9 @@ class MindplotWebComponent extends HTMLElement {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.setAttribute('class', 'wise-editor');
|
||||
wrapper.setAttribute('id', 'mindplot-canvas');
|
||||
wrapper.setAttribute('style', TopicStyle.defaultCanvasCssStyle());
|
||||
|
||||
const theme = ThemeFactory.createById('classic');
|
||||
wrapper.setAttribute('style', theme.getCanvasCssStyle());
|
||||
|
||||
this._shadowRoot.appendChild(wrapper);
|
||||
this._isLoaded = false;
|
||||
|
@ -21,7 +21,7 @@ import { Ellipse, Group } from '@wisemapping/web2d';
|
||||
import TopicConfig from './TopicConfig';
|
||||
import ActionDispatcher from './ActionDispatcher';
|
||||
import Topic from './Topic';
|
||||
import ColorUtil from './render/ColorUtil';
|
||||
import ColorUtil from './theme/ColorUtil';
|
||||
|
||||
class ShirinkConnector {
|
||||
private _isShrink: boolean;
|
||||
|
@ -20,7 +20,6 @@ import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import { Rect, Text, Group, ElementClass, ElementPeer } from '@wisemapping/web2d';
|
||||
|
||||
import NodeGraph, { NodeOption } from './NodeGraph';
|
||||
import TopicStyle from './TopicStyle';
|
||||
import TopicFeatureFactory from './TopicFeature';
|
||||
import ConnectionLine, { LineType } from './ConnectionLine';
|
||||
import IconGroup from './IconGroup';
|
||||
@ -40,11 +39,11 @@ import SizeType from './SizeType';
|
||||
import FeatureModel from './model/FeatureModel';
|
||||
import PositionType from './PositionType';
|
||||
import LineTopicShape from './widget/LineTopicShape';
|
||||
import ColorUtil from './render/ColorUtil';
|
||||
import Icon from './Icon';
|
||||
import { FontStyleType } from './FontStyleType';
|
||||
import { FontWeightType } from './FontWeightType';
|
||||
import DragTopic from './DragTopic';
|
||||
import ThemeFactory from './theme/ThemeFactory';
|
||||
|
||||
const ICON_SCALING_FACTOR = 1.3;
|
||||
|
||||
@ -119,83 +118,51 @@ abstract class Topic extends NodeGraph {
|
||||
}
|
||||
|
||||
protected redrawShapeType() {
|
||||
const oldInnerShape = this.getInnerShape();
|
||||
if (oldInnerShape) {
|
||||
this._removeInnerShape();
|
||||
this._removeInnerShape();
|
||||
|
||||
// Create a new one ...
|
||||
const innerShape = this.getInnerShape();
|
||||
// Create a new one ...
|
||||
const innerShape = this.getInnerShape();
|
||||
|
||||
// Update figure size ...
|
||||
const size = this.getSize();
|
||||
this.setSize(size, true);
|
||||
// Update figure size ...
|
||||
const size = this.getSize();
|
||||
this.setSize(size, true);
|
||||
|
||||
const group = this.get2DElement();
|
||||
group.append(innerShape);
|
||||
const group = this.get2DElement();
|
||||
group.append(innerShape);
|
||||
|
||||
// Move text to the front ...
|
||||
const text = this.getOrBuildTextShape();
|
||||
text.moveToFront();
|
||||
// Move text to the front ...
|
||||
const text = this.getOrBuildTextShape();
|
||||
text.moveToFront();
|
||||
|
||||
// Move iconGroup to front ...
|
||||
const iconGroup = this.getIconGroup();
|
||||
if (iconGroup) {
|
||||
iconGroup.moveToFront();
|
||||
}
|
||||
// Move iconGroup to front ...
|
||||
const iconGroup = this.getIconGroup();
|
||||
if (iconGroup) {
|
||||
iconGroup.moveToFront();
|
||||
}
|
||||
|
||||
// Move connector to front
|
||||
const connector = this.getShrinkConnector();
|
||||
if (connector) {
|
||||
connector.moveToFront();
|
||||
}
|
||||
// Move connector to front
|
||||
const connector = this.getShrinkConnector();
|
||||
if (connector) {
|
||||
connector.moveToFront();
|
||||
}
|
||||
}
|
||||
|
||||
getShapeType(): TopicShapeType {
|
||||
const model = this.getModel();
|
||||
let result = model.getShapeType();
|
||||
if (!result) {
|
||||
result = TopicStyle.defaultShapeType(this);
|
||||
}
|
||||
return result;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getShapeType(this);
|
||||
}
|
||||
|
||||
getConnectionStyle(): LineType {
|
||||
const model = this.getModel();
|
||||
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!;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getConnectionType(this);
|
||||
}
|
||||
|
||||
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 && parent.isCentralTopic()) {
|
||||
// This means that this is central main node, in this case, I will overwrite with the main color if it was defined.
|
||||
result = this.getModel().getConnectionColor() || parent.getModel().getConnectionColor();
|
||||
} else {
|
||||
result = parent?.getConnectionColor();
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = TopicStyle.defaultConnectionColor(this);
|
||||
}
|
||||
|
||||
return result!;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getConnectionColor(this);
|
||||
}
|
||||
|
||||
private _removeInnerShape(): ElementClass<ElementPeer> {
|
||||
@ -232,7 +199,7 @@ abstract class Topic extends NodeGraph {
|
||||
result = new Rect(0.9, { strokeWidth: 2 });
|
||||
break;
|
||||
case 'rounded rectangle':
|
||||
result = new Rect(0.3, { strokeWidth: 2 });
|
||||
result = new Rect(0.6, { strokeWidth: 2 });
|
||||
break;
|
||||
case 'line':
|
||||
result = new LineTopicShape(this, { strokeWidth: 2 });
|
||||
@ -300,14 +267,16 @@ abstract class Topic extends NodeGraph {
|
||||
}
|
||||
|
||||
private _buildIconGroup(): IconGroup {
|
||||
const model = this.getModel();
|
||||
const theme = ThemeFactory.create(model);
|
||||
|
||||
const textHeight = this.getOrBuildTextShape().getFontHeight();
|
||||
const iconSize = textHeight * ICON_SCALING_FACTOR;
|
||||
const result = new IconGroup(this.getId(), iconSize);
|
||||
const padding = TopicStyle.getInnerPadding(this);
|
||||
const padding = theme.getInnerPadding(this);
|
||||
result.setPosition(padding, padding);
|
||||
|
||||
// Load topic features ...
|
||||
const model = this.getModel();
|
||||
const featuresModel = model.getFeatures();
|
||||
|
||||
featuresModel.forEach((f) => {
|
||||
@ -397,78 +366,58 @@ abstract class Topic extends NodeGraph {
|
||||
const model = this.getModel();
|
||||
model.setFontFamily(value);
|
||||
|
||||
this.redraw();
|
||||
this.redraw(true);
|
||||
}
|
||||
|
||||
setFontSize(value: number): void {
|
||||
const model = this.getModel();
|
||||
model.setFontSize(value);
|
||||
|
||||
this.redraw();
|
||||
this.redraw(true);
|
||||
}
|
||||
|
||||
setFontStyle(value: FontStyleType): void {
|
||||
const model = this.getModel();
|
||||
model.setFontStyle(value);
|
||||
|
||||
this.redraw();
|
||||
this.redraw(true);
|
||||
}
|
||||
|
||||
setFontWeight(value: FontWeightType): void {
|
||||
const model = this.getModel();
|
||||
model.setFontWeight(value);
|
||||
|
||||
this.redraw();
|
||||
this.redraw(true);
|
||||
}
|
||||
|
||||
getFontWeight(): FontWeightType {
|
||||
const model = this.getModel();
|
||||
let result = model.getFontWeight();
|
||||
if (!result) {
|
||||
const font = TopicStyle.defaultFontStyle(this);
|
||||
result = font.weight;
|
||||
}
|
||||
return result;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getFontWeight(this);
|
||||
}
|
||||
|
||||
getFontFamily(): string {
|
||||
const model = this.getModel();
|
||||
let result = model.getFontFamily();
|
||||
if (!result) {
|
||||
const font = TopicStyle.defaultFontStyle(this);
|
||||
result = font.font;
|
||||
}
|
||||
return result;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getFontFamily(this);
|
||||
}
|
||||
|
||||
getFontColor(): string {
|
||||
const model = this.getModel();
|
||||
let result = model.getFontColor();
|
||||
if (!result) {
|
||||
const font = TopicStyle.defaultFontStyle(this);
|
||||
result = font.color;
|
||||
}
|
||||
return result;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getFontColor(this);
|
||||
}
|
||||
|
||||
getFontStyle(): string {
|
||||
getFontStyle(): FontStyleType {
|
||||
const model = this.getModel();
|
||||
let result = model.getFontStyle();
|
||||
if (!result) {
|
||||
const font = TopicStyle.defaultFontStyle(this);
|
||||
result = font.style;
|
||||
}
|
||||
return result;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getFontStyle(this);
|
||||
}
|
||||
|
||||
getFontSize(): number {
|
||||
const model = this.getModel();
|
||||
let result = model.getFontSize();
|
||||
if (!result) {
|
||||
const font = TopicStyle.defaultFontStyle(this);
|
||||
result = font.size;
|
||||
}
|
||||
return result;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getFontSize(this);
|
||||
}
|
||||
|
||||
setFontColor(value: string | undefined) {
|
||||
@ -485,20 +434,22 @@ abstract class Topic extends NodeGraph {
|
||||
const model = this.getModel();
|
||||
model.setText(modelText);
|
||||
|
||||
this.redraw();
|
||||
this.redraw(true);
|
||||
}
|
||||
|
||||
getText(): string {
|
||||
const model = this.getModel();
|
||||
const theme = ThemeFactory.create(model);
|
||||
|
||||
const text = model.getText();
|
||||
return text || TopicStyle.defaultText(this);
|
||||
return text || theme.getText(this);
|
||||
}
|
||||
|
||||
setBackgroundColor(color: string | undefined): void {
|
||||
const model = this.getModel();
|
||||
model.setBackgroundColor(color);
|
||||
|
||||
this.redraw();
|
||||
this.redraw(true);
|
||||
}
|
||||
|
||||
setConnectionStyle(type: LineType): void {
|
||||
@ -517,19 +468,8 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
getBackgroundColor(): string {
|
||||
const model = this.getModel();
|
||||
let result = model.getBackgroundColor();
|
||||
if (!result && !this.isCentralTopic()) {
|
||||
// Be sure that not overwride default background color ...
|
||||
const borderColor = model.getBorderColor();
|
||||
if (borderColor) {
|
||||
result = ColorUtil.lightenColor(borderColor, 40);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = TopicStyle.defaultBackgroundColor(this);
|
||||
}
|
||||
return result;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getBackgroundColor(this);
|
||||
}
|
||||
|
||||
setBorderColor(color: string | undefined): void {
|
||||
@ -541,25 +481,8 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
getBorderColor(): string {
|
||||
const model = this.getModel();
|
||||
let result = model.getBorderColor();
|
||||
|
||||
// If the the style is a line, the color is alward the connection one.
|
||||
if (this.getShapeType() === 'line') {
|
||||
result = this.getConnectionColor();
|
||||
}
|
||||
|
||||
if (result === undefined) {
|
||||
const parent = this.getParent();
|
||||
if (parent) {
|
||||
result = parent.getBorderColor();
|
||||
}
|
||||
}
|
||||
|
||||
// If border color has not been defined, use the connection color for the border ...
|
||||
if (!result) {
|
||||
result = this.getConnectionColor();
|
||||
}
|
||||
return result;
|
||||
const theme = ThemeFactory.create(model);
|
||||
return theme.getBorderColor(this);
|
||||
}
|
||||
|
||||
_buildTopicShape(): void {
|
||||
@ -638,11 +561,12 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
setOnFocus(focus: boolean) {
|
||||
if (this.isOnFocus() !== focus) {
|
||||
const theme = ThemeFactory.create(this.getModel());
|
||||
this._onFocus = focus;
|
||||
const outerShape = this.getOuterShape();
|
||||
|
||||
const fillColor = TopicStyle.defaultOuterBackgroundColor(this, focus);
|
||||
const borderColor = TopicStyle.defaultOuterBorderColor(this);
|
||||
const fillColor = theme.getOuterBackgroundColor(this, focus);
|
||||
const borderColor = theme.getOuterBorderColor(this);
|
||||
|
||||
outerShape.setFill(fillColor);
|
||||
outerShape.setStroke(1, 'solid', borderColor);
|
||||
@ -1051,7 +975,7 @@ abstract class Topic extends NodeGraph {
|
||||
}
|
||||
}
|
||||
|
||||
getOrder(): number {
|
||||
getOrder(): number | undefined {
|
||||
const model = this.getModel();
|
||||
return model.getOrder();
|
||||
}
|
||||
@ -1184,6 +1108,7 @@ abstract class Topic extends NodeGraph {
|
||||
// Has the style change ?
|
||||
const connStyleChanged =
|
||||
this._outgoingLine.getLineType() !== this.getParent()!.getConnectionStyle();
|
||||
|
||||
if (connStyleChanged) {
|
||||
// Todo: Review static reference ...
|
||||
const workspace = designer.getWorkSpace();
|
||||
@ -1197,13 +1122,8 @@ abstract class Topic extends NodeGraph {
|
||||
result = true;
|
||||
}
|
||||
|
||||
// Has the color changed ?
|
||||
const color = this._outgoingLine.getStrokeColor();
|
||||
const connColorChanged = color !== this.getParent()!.getConnectionColor();
|
||||
if (connColorChanged) {
|
||||
this._outgoingLine.redraw();
|
||||
result = true;
|
||||
}
|
||||
this._outgoingLine.redraw();
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -1211,6 +1131,7 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
redraw(redrawChildren = false): void {
|
||||
if (this._isInWorkspace) {
|
||||
const theme = ThemeFactory.create(this.getModel());
|
||||
const textShape = this.getOrBuildTextShape();
|
||||
// Update font ...
|
||||
const fontColor = this.getFontColor();
|
||||
@ -1233,8 +1154,8 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
// Update outer shape style ...
|
||||
const outerShape = this.getOuterShape();
|
||||
const outerFillColor = TopicStyle.defaultOuterBackgroundColor(this, this.isOnFocus());
|
||||
const outerBorderColor = TopicStyle.defaultOuterBorderColor(this);
|
||||
const outerFillColor = theme.getOuterBackgroundColor(this, this.isOnFocus());
|
||||
const outerBorderColor = theme.getOuterBorderColor(this);
|
||||
|
||||
outerShape.setFill(outerFillColor);
|
||||
outerShape.setStroke(1, 'solid', outerBorderColor);
|
||||
@ -1242,7 +1163,7 @@ abstract class Topic extends NodeGraph {
|
||||
// Calculate topic size and adjust elements ...
|
||||
const textWidth = textShape.getShapeWidth();
|
||||
const textHeight = textShape.getShapeHeight();
|
||||
const padding = TopicStyle.getInnerPadding(this);
|
||||
const padding = theme.getInnerPadding(this);
|
||||
|
||||
// Adjust icons group based on the font size ...
|
||||
const iconGroup = this.getOrBuildIconGroup();
|
||||
|
@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { $assert } from '@wisemapping/core-js';
|
||||
import { LineType } from './ConnectionLine';
|
||||
import { FontStyleType } from './FontStyleType';
|
||||
import { FontWeightType } from './FontWeightType';
|
||||
import { $msg } from './Messages';
|
||||
import { TopicShapeType } from './model/INodeModel';
|
||||
import ColorUtil from './render/ColorUtil';
|
||||
import Topic from './Topic';
|
||||
|
||||
type FontStyle = {
|
||||
font: string;
|
||||
size: number;
|
||||
style: FontStyleType;
|
||||
weight: FontWeightType;
|
||||
color: string;
|
||||
};
|
||||
|
||||
type TopicStyleType = {
|
||||
borderColor: string;
|
||||
backgroundColor: string;
|
||||
connectionStyle: LineType;
|
||||
connectionColor: string;
|
||||
fontStyle: FontStyle;
|
||||
msgKey: string;
|
||||
shapeType: TopicShapeType;
|
||||
};
|
||||
|
||||
const TopicDefaultStyles = {
|
||||
CENTRAL_TOPIC: {
|
||||
borderColor: '#3971B1',
|
||||
backgroundColor: '#509DC0',
|
||||
fontStyle: {
|
||||
font: 'Verdana',
|
||||
size: 10,
|
||||
style: 'normal' as FontStyleType,
|
||||
weight: 'bold' as FontWeightType,
|
||||
color: '#ffffff',
|
||||
},
|
||||
connectionStyle: LineType.THICK_CURVED,
|
||||
connectionColor: '#345780',
|
||||
msgKey: 'CENTRAL_TOPIC',
|
||||
shapeType: 'rounded rectangle' as TopicShapeType,
|
||||
},
|
||||
MAIN_TOPIC: {
|
||||
borderColor: '#023BB9',
|
||||
backgroundColor: '#E0E5EF',
|
||||
fontStyle: {
|
||||
font: 'Verdana',
|
||||
size: 8,
|
||||
style: 'normal' as FontStyleType,
|
||||
weight: 'normal' as FontWeightType,
|
||||
color: '#525C61',
|
||||
},
|
||||
connectionStyle: LineType.ARC,
|
||||
connectionColor: '#345780',
|
||||
msgKey: 'MAIN_TOPIC',
|
||||
shapeType: 'line' as TopicShapeType,
|
||||
},
|
||||
SUB_TOPIC: {
|
||||
borderColor: '#96e3ff',
|
||||
backgroundColor: '#96e3ff',
|
||||
fontStyle: {
|
||||
font: 'Verdana',
|
||||
size: 8,
|
||||
style: 'normal' as FontStyleType,
|
||||
weight: 'normal' as FontWeightType,
|
||||
color: '#525C61',
|
||||
},
|
||||
connectionStyle: LineType.ARC,
|
||||
connectionColor: '#345780',
|
||||
msgKey: 'SUB_TOPIC',
|
||||
shapeType: 'line' as TopicShapeType,
|
||||
},
|
||||
|
||||
ISOLATED_TOPIC: {
|
||||
borderColor: '#023BB9',
|
||||
backgroundColor: '#96e3ff',
|
||||
fontStyle: {
|
||||
font: 'Verdana',
|
||||
size: 8,
|
||||
style: 'normal' as FontStyleType,
|
||||
weight: 'normal' as FontWeightType,
|
||||
color: '#525C61',
|
||||
},
|
||||
msgKey: 'ISOLATED_TOPIC',
|
||||
connectionStyle: LineType.THICK_CURVED,
|
||||
connectionColor: '#345780',
|
||||
shapeType: 'line' as TopicShapeType,
|
||||
},
|
||||
};
|
||||
|
||||
class TopicStyle {
|
||||
static _getStyles(topic: Topic): TopicStyleType {
|
||||
$assert(topic, 'topic can not be null');
|
||||
|
||||
let result: TopicStyleType;
|
||||
if (topic.isCentralTopic()) {
|
||||
result = TopicDefaultStyles.CENTRAL_TOPIC;
|
||||
} else {
|
||||
const targetTopic = topic.getOutgoingConnectedTopic();
|
||||
if (targetTopic) {
|
||||
if (targetTopic.isCentralTopic()) {
|
||||
result = TopicDefaultStyles.MAIN_TOPIC;
|
||||
} else {
|
||||
result = TopicDefaultStyles.SUB_TOPIC;
|
||||
}
|
||||
} else {
|
||||
result = TopicDefaultStyles.ISOLATED_TOPIC;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static defaultText(topic: Topic): string {
|
||||
const { msgKey } = this._getStyles(topic);
|
||||
return $msg(msgKey);
|
||||
}
|
||||
|
||||
static defaultFontStyle(topic: Topic): FontStyle {
|
||||
return this._getStyles(topic).fontStyle;
|
||||
}
|
||||
|
||||
static defaultCanvasCssStyle(): string {
|
||||
return `position: relative;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
background-color: #f2f2f2;
|
||||
background-image: linear-gradient(#ebe9e7 1px, transparent 1px),
|
||||
linear-gradient(to right, #ebe9e7 1px, #f2f2f2 1px);
|
||||
background-size: 50px 50px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;`;
|
||||
}
|
||||
|
||||
static defaultOuterBorderColor(topic: Topic): string {
|
||||
let result: string;
|
||||
if (topic.getShapeType() === 'line') {
|
||||
result = '#F4B82D';
|
||||
} else {
|
||||
const innerBorderColor = topic.getBorderColor();
|
||||
result = ColorUtil.lightenColor(innerBorderColor, 70);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static defaultOuterBackgroundColor(topic: Topic, onFocus: boolean): string {
|
||||
let result: string;
|
||||
if (topic.getShapeType() === 'line') {
|
||||
result = onFocus ? '#F4B82D' : '#FCEBC0';
|
||||
} else {
|
||||
const innerBgColor = topic.getBackgroundColor();
|
||||
result = ColorUtil.lightenColor(innerBgColor, 70);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static defaultBackgroundColor(topic: Topic): string {
|
||||
return this._getStyles(topic).backgroundColor;
|
||||
}
|
||||
|
||||
static defaultBorderColor(topic: Topic): string {
|
||||
return this._getStyles(topic).borderColor;
|
||||
}
|
||||
|
||||
static getInnerPadding(topic: Topic): number {
|
||||
return topic.getOrBuildTextShape().getFontHeight() * 0.5;
|
||||
}
|
||||
|
||||
static defaultShapeType(topic: Topic): TopicShapeType {
|
||||
return this._getStyles(topic).shapeType;
|
||||
}
|
||||
|
||||
static defaultConnectionType(topic: Topic): LineType {
|
||||
return this._getStyles(topic).connectionStyle;
|
||||
}
|
||||
|
||||
static defaultConnectionColor(topic: Topic): string {
|
||||
return this._getStyles(topic).connectionColor;
|
||||
}
|
||||
}
|
||||
|
||||
export default TopicStyle;
|
@ -15,6 +15,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { $defined } from '@wisemapping/core-js';
|
||||
import Command from '../Command';
|
||||
import CommandContext from '../CommandContext';
|
||||
import PositionType from '../PositionType';
|
||||
@ -27,7 +28,7 @@ class DragTopicCommand extends Command {
|
||||
|
||||
private _position: PositionType;
|
||||
|
||||
private _order: number;
|
||||
private _order: number | undefined;
|
||||
|
||||
constructor(topicId: number, position: PositionType, order: number, parentTopic: Topic) {
|
||||
super();
|
||||
@ -55,8 +56,8 @@ class DragTopicCommand extends Command {
|
||||
}
|
||||
|
||||
// Set topic order ...
|
||||
if (this._order != null) {
|
||||
topic.setOrder(this._order);
|
||||
if ($defined(this._order)) {
|
||||
topic.setOrder(this._order!);
|
||||
} else if (this._position != null) {
|
||||
commandContext.moveTopic(topic, this._position);
|
||||
} else {
|
||||
|
@ -124,7 +124,8 @@ export default class FreemindImporter extends Importer {
|
||||
relationship.setSrcCtrlPoint({ x, y: coords.y });
|
||||
|
||||
// Fix coord
|
||||
if (srcTopic.getOrder() && srcTopic.getOrder() % 2 !== 0) {
|
||||
const order = srcTopic.getOrder();
|
||||
if (order !== undefined && order % 2 !== 0) {
|
||||
const y = coords.y * -1;
|
||||
relationship.setSrcCtrlPoint({ x: coords.x, y });
|
||||
}
|
||||
@ -140,7 +141,8 @@ export default class FreemindImporter extends Importer {
|
||||
relationship.setDestCtrlPoint({ x, y: coords.y });
|
||||
}
|
||||
|
||||
if (destNode.getOrder() && destNode.getOrder() % 2 !== 0) {
|
||||
const order = destNode.getOrder();
|
||||
if (order !== undefined && order % 2 !== 0) {
|
||||
const y = coords.y * -1;
|
||||
relationship.setDestCtrlPoint({ x: coords.x, y });
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ abstract class ChildrenSorterStrategy {
|
||||
|
||||
abstract computeOffsets(treeSet: RootedTreeSet, node: Node): Map<number, PositionType>;
|
||||
|
||||
abstract insert(treeSet: RootedTreeSet, parent: Node, child: Node, order: number): void;
|
||||
abstract insert(treeSet: RootedTreeSet, parent: Node, child: Node, order?: number): void;
|
||||
|
||||
abstract detach(treeSet: RootedTreeSet, node: Node): void;
|
||||
|
||||
|
@ -60,7 +60,7 @@ class EventBusDispatcher {
|
||||
this._layoutManager!.connectNode(
|
||||
args.parentNode.getId(),
|
||||
args.childNode.getId(),
|
||||
args.childNode.getOrder(),
|
||||
args.childNode.getOrder()!, // @todo: This can be a issue ...
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -114,6 +114,7 @@ class OriginalLayout {
|
||||
const parentX = parentPosition.x;
|
||||
const parentY = parentPosition.y;
|
||||
|
||||
console.log(`${parent?.getId()}:${offset.x}`);
|
||||
const newPos = {
|
||||
x: parentX + offset.x,
|
||||
y: parentY + offset.y + this.calculateAlignOffset(node, child, heightById),
|
||||
@ -174,6 +175,9 @@ class OriginalLayout {
|
||||
private fixOverlapping(node: Node, heightById: Map<number, number>): void {
|
||||
const children = this._treeSet.getChildren(node);
|
||||
|
||||
if (node.isFree()) {
|
||||
this._shiftBranches(node, heightById);
|
||||
}
|
||||
children.forEach((child) => {
|
||||
this.fixOverlapping(child, heightById);
|
||||
});
|
||||
|
@ -137,7 +137,8 @@ abstract class INodeModel {
|
||||
}
|
||||
|
||||
getShapeType(): TopicShapeType {
|
||||
return this.getProperty('shapeType') as TopicShapeType;
|
||||
const result = this.getProperty('shapeType') as TopicShapeType;
|
||||
return result;
|
||||
}
|
||||
|
||||
setShapeType(type: TopicShapeType | undefined) {
|
||||
@ -152,7 +153,7 @@ abstract class INodeModel {
|
||||
this.putProperty('order', value);
|
||||
}
|
||||
|
||||
getOrder(): number {
|
||||
getOrder(): number | undefined {
|
||||
return this.getProperty('order') as number;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import INodeModel, { NodeModelType } from './INodeModel';
|
||||
import NodeModel from './NodeModel';
|
||||
import RelationshipModel from './RelationshipModel';
|
||||
import ModelCodeName from '../persistence/ModelCodeName';
|
||||
import ThemeType from './ThemeType';
|
||||
|
||||
class Mindmap extends IMindmap {
|
||||
private _description: string;
|
||||
@ -33,6 +34,8 @@ class Mindmap extends IMindmap {
|
||||
|
||||
private _relationships: Array<RelationshipModel>;
|
||||
|
||||
private _theme: ThemeType | undefined;
|
||||
|
||||
constructor(id?: string, version: string = ModelCodeName.TANGO) {
|
||||
super();
|
||||
this._branches = [];
|
||||
@ -42,6 +45,10 @@ class Mindmap extends IMindmap {
|
||||
this._id = id;
|
||||
}
|
||||
|
||||
getTheme(): ThemeType {
|
||||
return this._theme ? this._theme : 'classic';
|
||||
}
|
||||
|
||||
/** */
|
||||
getDescription(): string {
|
||||
return this._description;
|
||||
|
@ -132,46 +132,6 @@ 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 backgroundColor = value.getBackgroundColor();
|
||||
if (backgroundColor) {
|
||||
this.setBackgroundColor(backgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
deepCopy(): NodeModel {
|
||||
const result = new NodeModel(this.getType(), this._mindmap);
|
||||
result._children = this._children.map((node) => {
|
||||
|
20
packages/mindplot/src/components/model/ThemeType.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright [2021] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
type ThemeType = 'classic' | 'prism';
|
||||
|
||||
export default ThemeType;
|
@ -59,8 +59,8 @@ class Pela2TangoMigrator implements XMLMindmapSerializer {
|
||||
} else {
|
||||
rightNodes.push(child);
|
||||
}
|
||||
rightNodes.sort((a, b) => a.getOrder() - b.getOrder());
|
||||
leftNodes.sort((a, b) => a.getOrder() - b.getOrder());
|
||||
rightNodes.sort((a, b) => a.getOrder()! - b.getOrder()!);
|
||||
leftNodes.sort((a, b) => a.getOrder()! - b.getOrder()!);
|
||||
});
|
||||
|
||||
for (let i = 0; i < rightNodes.length; i++) {
|
||||
|
@ -60,7 +60,9 @@ class XMLSerializerBeta implements XMLMindmapSerializer {
|
||||
parentTopic.setAttribute('position', `${pos.x},${pos.y}`);
|
||||
} else {
|
||||
const order = topic.getOrder();
|
||||
parentTopic.setAttribute('order', order.toString());
|
||||
if (order !== undefined) {
|
||||
parentTopic.setAttribute('order', order.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -452,7 +452,7 @@ class XMLSerializerTango implements XMLMindmapSerializer {
|
||||
if (topic.getType() !== 'CentralTopic') {
|
||||
topic
|
||||
.getChildren()
|
||||
.sort((a, b) => a.getOrder() - b.getOrder())
|
||||
.sort((a, b) => a.getOrder()! - b.getOrder()!)
|
||||
.forEach((child, index) => {
|
||||
if (child.getOrder() !== index) {
|
||||
child.setOrder(index);
|
||||
|
124
packages/mindplot/src/components/theme/ClassicTheme.ts
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { LineType } from '../ConnectionLine';
|
||||
import { FontStyleType } from '../FontStyleType';
|
||||
import { FontWeightType } from '../FontWeightType';
|
||||
import { TopicShapeType } from '../model/INodeModel';
|
||||
import DefaultTheme, { TopicStyleType } from './DefaultTheme';
|
||||
import { TopicType } from './Theme';
|
||||
|
||||
const defaultStyles = new Map<TopicType, TopicStyleType>([
|
||||
[
|
||||
'CentralTopic',
|
||||
{
|
||||
msgKey: 'CENTRAL_TOPIC',
|
||||
borderColor: '#3971B1',
|
||||
backgroundColor: '#509DC0',
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: 10,
|
||||
fontStyle: 'normal' as FontStyleType,
|
||||
fontWeight: 'bold' as FontWeightType,
|
||||
fontColor: '#ffffff',
|
||||
connectionStyle: LineType.THICK_CURVED,
|
||||
connectionColor: '#345780',
|
||||
shapeType: 'rounded rectangle' as TopicShapeType,
|
||||
outerBackgroundColor: '#F4B82D',
|
||||
outerBorderColor: '#F4B82D',
|
||||
},
|
||||
],
|
||||
[
|
||||
'MainTopic',
|
||||
{
|
||||
msgKey: 'MAIN_TOPIC',
|
||||
borderColor: '#023BB9',
|
||||
backgroundColor: '#E0E5EF',
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: 9,
|
||||
fontStyle: 'normal' as FontStyleType,
|
||||
fontWeight: 'normal' as FontWeightType,
|
||||
fontColor: '#525C61',
|
||||
connectionStyle: LineType.THICK_CURVED,
|
||||
connectionColor: '#345780',
|
||||
shapeType: 'line' as TopicShapeType,
|
||||
outerBackgroundColor: '#F4B82D',
|
||||
outerBorderColor: '#F4B82D',
|
||||
},
|
||||
],
|
||||
[
|
||||
'SubTopic',
|
||||
{
|
||||
msgKey: 'SUB_TOPIC',
|
||||
borderColor: '#96e3ff',
|
||||
backgroundColor: '#96e3ff',
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: 8,
|
||||
fontStyle: 'normal' as FontStyleType,
|
||||
fontWeight: 'normal' as FontWeightType,
|
||||
fontColor: '#525C61',
|
||||
connectionStyle: LineType.THICK_CURVED,
|
||||
connectionColor: '#345780',
|
||||
shapeType: 'line' as TopicShapeType,
|
||||
outerBackgroundColor: '#F4B82D',
|
||||
outerBorderColor: '#F4B82D',
|
||||
},
|
||||
],
|
||||
[
|
||||
'IsolatedTopic',
|
||||
{
|
||||
msgKey: 'ISOLATED_TOPIC',
|
||||
borderColor: '#023BB9',
|
||||
backgroundColor: '#96e3ff',
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: 8,
|
||||
fontStyle: 'normal' as FontStyleType,
|
||||
fontWeight: 'normal' as FontWeightType,
|
||||
fontColor: '#525C61',
|
||||
connectionStyle: LineType.THICK_CURVED,
|
||||
connectionColor: '#345780',
|
||||
shapeType: 'line' as TopicShapeType,
|
||||
outerBackgroundColor: '#F4B82D',
|
||||
outerBorderColor: '#F4B82D',
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
class ClassicTheme extends DefaultTheme {
|
||||
constructor() {
|
||||
super(defaultStyles);
|
||||
}
|
||||
|
||||
getCanvasCssStyle(): string {
|
||||
return `position: relative;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
background-color: #f2f2f2;
|
||||
background-image: linear-gradient(#ebe9e7 1px, transparent 1px),
|
||||
linear-gradient(to right, #ebe9e7 1px, #f2f2f2 1px);
|
||||
background-size: 50px 50px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;`;
|
||||
}
|
||||
}
|
||||
|
||||
export default ClassicTheme;
|
247
packages/mindplot/src/components/theme/DefaultTheme.ts
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright [2021] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { LineType } from '../ConnectionLine';
|
||||
import { FontStyleType } from '../FontStyleType';
|
||||
import { FontWeightType } from '../FontWeightType';
|
||||
import { TopicShapeType } from '../model/INodeModel';
|
||||
import NodeModel from '../model/NodeModel';
|
||||
import ColorUtil from './ColorUtil';
|
||||
import Topic from '../Topic';
|
||||
import Theme, { TopicType } from './Theme';
|
||||
import { $msg } from '../Messages';
|
||||
|
||||
export type TopicStyleType = {
|
||||
borderColor: string | string[];
|
||||
backgroundColor: string | string[];
|
||||
connectionColor: string | string[];
|
||||
connectionStyle: LineType;
|
||||
fontFamily: string;
|
||||
fontSize: number;
|
||||
fontStyle: FontStyleType;
|
||||
fontWeight: FontWeightType;
|
||||
fontColor: string;
|
||||
msgKey: string;
|
||||
shapeType: TopicShapeType;
|
||||
outerBackgroundColor: string;
|
||||
outerBorderColor: string;
|
||||
};
|
||||
|
||||
type StyleType = string | string[] | number | undefined | LineType;
|
||||
|
||||
const keyToModel = new Map<keyof TopicStyleType, (model: NodeModel) => StyleType>([
|
||||
['borderColor', (m: NodeModel) => m.getBorderColor()],
|
||||
['backgroundColor', (m: NodeModel) => m.getBackgroundColor()],
|
||||
['shapeType', (m: NodeModel) => m.getShapeType()],
|
||||
['connectionStyle', (m: NodeModel) => m.getConnectionStyle()],
|
||||
['connectionColor', (m: NodeModel) => m.getConnectionColor()],
|
||||
['fontFamily', (m: NodeModel) => m.getFontFamily()],
|
||||
['fontColor', (m: NodeModel) => m.getFontColor()],
|
||||
['fontWeight', (m: NodeModel) => m.getFontWeight()],
|
||||
['fontSize', (m: NodeModel) => m.getFontSize()],
|
||||
['fontStyle', (m: NodeModel) => m.getFontStyle()],
|
||||
]);
|
||||
|
||||
abstract class DefaultTheme implements Theme {
|
||||
private _style: Map<TopicType, TopicStyleType>;
|
||||
|
||||
constructor(style: Map<TopicType, TopicStyleType>) {
|
||||
this._style = style;
|
||||
}
|
||||
|
||||
abstract getCanvasCssStyle(): string;
|
||||
|
||||
protected resolve(key: keyof TopicStyleType, topic: Topic, resolveDefault = true): StyleType {
|
||||
// Search parent value ...
|
||||
const recurviveModelStrategy = (value: keyof TopicStyleType, t: Topic): StyleType => {
|
||||
const model = t.getModel();
|
||||
let result: StyleType = keyToModel.get(key)!(model);
|
||||
|
||||
const parent = t.getParent();
|
||||
if (!result && parent) {
|
||||
result = recurviveModelStrategy(value, parent);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Can be found in the model or parent ?
|
||||
let result = recurviveModelStrategy(key, topic);
|
||||
if (!result && resolveDefault) {
|
||||
result = this.getStyles(topic)[key];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected getStyles(topic: Topic): TopicStyleType {
|
||||
let result: TopicStyleType;
|
||||
if (topic.isCentralTopic()) {
|
||||
result = this._style.get('CentralTopic')!;
|
||||
} else {
|
||||
const targetTopic = topic.getOutgoingConnectedTopic();
|
||||
if (targetTopic) {
|
||||
if (targetTopic.isCentralTopic()) {
|
||||
result = this._style.get('MainTopic')!;
|
||||
} else {
|
||||
result = this._style.get('SubTopic')!;
|
||||
}
|
||||
} else {
|
||||
result = this._style.get('IsolatedTopic')!;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
getBackgroundColor(topic: Topic): string {
|
||||
const model = topic.getModel();
|
||||
let result = model.getBackgroundColor();
|
||||
if (!result && !topic.isCentralTopic()) {
|
||||
// Be sure that not overwride default background color ...
|
||||
const borderColor = model.getBorderColor();
|
||||
if (borderColor) {
|
||||
result = ColorUtil.lightenColor(borderColor, 40);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
let colors: string[] = [];
|
||||
colors = colors.concat(this.resolve('backgroundColor', topic) as string[] | string);
|
||||
|
||||
// if the element is an array, use topic order to decide color ..
|
||||
let order = topic.getOrder();
|
||||
order = order || 0;
|
||||
|
||||
const index = order % colors.length;
|
||||
result = colors[index];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
getShapeType(topic: Topic): TopicShapeType {
|
||||
const result = this.resolve('shapeType', topic) as TopicShapeType;
|
||||
return result;
|
||||
}
|
||||
|
||||
getConnectionType(topic: Topic): LineType {
|
||||
return this.resolve('connectionStyle', topic) as LineType;
|
||||
}
|
||||
|
||||
getFontFamily(topic: Topic): string {
|
||||
return this.resolve('fontFamily', topic) as string;
|
||||
}
|
||||
|
||||
getFontSize(topic: Topic): number {
|
||||
return this.resolve('fontSize', topic) as number;
|
||||
}
|
||||
|
||||
getFontStyle(topic: Topic): FontStyleType {
|
||||
return this.resolve('fontStyle', topic) as FontStyleType;
|
||||
}
|
||||
|
||||
getFontWeight(topic: Topic): FontWeightType {
|
||||
return this.resolve('fontWeight', topic) as FontWeightType;
|
||||
}
|
||||
|
||||
getFontColor(topic: Topic): string {
|
||||
return this.resolve('fontColor', topic) as string;
|
||||
}
|
||||
|
||||
getBorderColor(topic: Topic): string {
|
||||
const model = topic.getModel();
|
||||
let result = model.getBorderColor();
|
||||
|
||||
// If the the style is a line, the color is alward the connection one.
|
||||
if (topic.getShapeType() === 'line') {
|
||||
result = topic.getConnectionColor();
|
||||
}
|
||||
|
||||
if (result === undefined) {
|
||||
const parent = topic.getParent();
|
||||
if (parent) {
|
||||
result = parent.getBorderColor();
|
||||
}
|
||||
}
|
||||
|
||||
// If border color has not been defined, use the connection color for the border ...
|
||||
if (!result) {
|
||||
result = topic.getConnectionColor();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
getOuterBorderColor(topic: Topic): string {
|
||||
let result: string;
|
||||
if (topic.getShapeType() === 'line') {
|
||||
result = this.getStyles(topic).outerBorderColor;
|
||||
} else {
|
||||
const innerBorderColor = topic.getBorderColor();
|
||||
result = ColorUtil.lightenColor(innerBorderColor, 70);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
getOuterBackgroundColor(topic: Topic, onFocus: boolean): string {
|
||||
let result: string;
|
||||
if (topic.getShapeType() === 'line') {
|
||||
const color = this.getStyles(topic).outerBackgroundColor;
|
||||
result = onFocus ? color : ColorUtil.lightenColor(color, 30);
|
||||
} else {
|
||||
const innerBgColor = topic.getBackgroundColor();
|
||||
result = ColorUtil.lightenColor(innerBgColor, 70);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
getInnerPadding(topic: Topic): number {
|
||||
return topic.getOrBuildTextShape().getFontHeight() * 0.5;
|
||||
}
|
||||
|
||||
getText(topic: Topic): string {
|
||||
const { msgKey } = this.getStyles(topic);
|
||||
return $msg(msgKey);
|
||||
}
|
||||
|
||||
getConnectionColor(topic: Topic): string {
|
||||
const model = topic.getModel();
|
||||
let result: string | undefined = model.getConnectionColor();
|
||||
|
||||
// Style is infered looking recursivelly on the parent nodes.
|
||||
if (!result) {
|
||||
const parent = topic.getParent();
|
||||
if (parent && parent.isCentralTopic()) {
|
||||
// This means that this is central main node, in this case, I will overwrite with the main color if it was defined.
|
||||
result = topic.getModel().getConnectionColor() || parent.getModel().getConnectionColor();
|
||||
} else {
|
||||
result = parent?.getConnectionColor();
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
let colors: string[] = [];
|
||||
colors = colors.concat(this.resolve('connectionColor', topic) as string[] | string);
|
||||
|
||||
// if the element is an array, use topic order to decide color ..
|
||||
let order = topic.getOrder();
|
||||
order = order || 0;
|
||||
|
||||
const index = order % colors.length;
|
||||
result = colors[index];
|
||||
}
|
||||
return result!;
|
||||
}
|
||||
}
|
||||
export default DefaultTheme;
|
201
packages/mindplot/src/components/theme/PrismTheme.ts
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright [2011] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { LineType } from '../ConnectionLine';
|
||||
import { FontStyleType } from '../FontStyleType';
|
||||
import { FontWeightType } from '../FontWeightType';
|
||||
import { TopicShapeType } from '../model/INodeModel';
|
||||
import Topic from '../Topic';
|
||||
import DefaultTheme, { TopicStyleType } from './DefaultTheme';
|
||||
import { TopicType } from './Theme';
|
||||
|
||||
const defaultStyles = new Map<TopicType, TopicStyleType>([
|
||||
[
|
||||
'CentralTopic',
|
||||
{
|
||||
msgKey: 'CENTRAL_TOPIC',
|
||||
borderColor: '#FFFFFF',
|
||||
backgroundColor: '#FFFFFF',
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: 10,
|
||||
fontStyle: 'normal' as FontStyleType,
|
||||
fontWeight: 'bold' as FontWeightType,
|
||||
fontColor: '#000000',
|
||||
connectionStyle: LineType.ARC,
|
||||
connectionColor: '#345780',
|
||||
shapeType: 'rounded rectangle' as TopicShapeType,
|
||||
outerBackgroundColor: '#F4B82D',
|
||||
outerBorderColor: '#F4B82D',
|
||||
},
|
||||
],
|
||||
[
|
||||
'MainTopic',
|
||||
{
|
||||
msgKey: 'MAIN_TOPIC',
|
||||
borderColor: [
|
||||
'#9B7BEB',
|
||||
'#E5628C',
|
||||
'#EB5130',
|
||||
'#F3AE3D',
|
||||
'#F8D651',
|
||||
'#A5D945',
|
||||
'#6BC953',
|
||||
'#6AD6D7',
|
||||
'#4CA6F7',
|
||||
'#4B6FF6',
|
||||
],
|
||||
backgroundColor: [
|
||||
'#9B7BEB',
|
||||
'#E5628C',
|
||||
'#EB5130',
|
||||
'#F3AE3D',
|
||||
'#F8D651',
|
||||
'#A5D945',
|
||||
'#6BC953',
|
||||
'#6AD6D7',
|
||||
'#4CA6F7',
|
||||
'#4B6FF6',
|
||||
],
|
||||
connectionColor: [
|
||||
'#9B7BEB',
|
||||
'#E5628C',
|
||||
'#EB5130',
|
||||
'#F3AE3D',
|
||||
'#F8D651',
|
||||
'#A5D945',
|
||||
'#6BC953',
|
||||
'#6AD6D7',
|
||||
'#4CA6F7',
|
||||
'#4B6FF6',
|
||||
],
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: 9,
|
||||
fontStyle: 'normal' as FontStyleType,
|
||||
fontWeight: 'normal' as FontWeightType,
|
||||
fontColor: '#000000',
|
||||
connectionStyle: LineType.ARC,
|
||||
shapeType: 'rounded rectangle' as TopicShapeType,
|
||||
outerBackgroundColor: '#F4B82D',
|
||||
outerBorderColor: '#F4B82D',
|
||||
},
|
||||
],
|
||||
[
|
||||
'SubTopic',
|
||||
{
|
||||
msgKey: 'SUB_TOPIC',
|
||||
borderColor: '#96e3ff',
|
||||
backgroundColor: '#96e3ff',
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: 8,
|
||||
fontStyle: 'normal' as FontStyleType,
|
||||
fontWeight: 'normal' as FontWeightType,
|
||||
fontColor: '#000000',
|
||||
connectionStyle: LineType.THICK_CURVED,
|
||||
connectionColor: '#345780',
|
||||
shapeType: 'line' as TopicShapeType,
|
||||
outerBackgroundColor: '#F4B82D',
|
||||
outerBorderColor: '#F4B82D',
|
||||
},
|
||||
],
|
||||
[
|
||||
'IsolatedTopic',
|
||||
{
|
||||
msgKey: 'ISOLATED_TOPIC',
|
||||
borderColor: '#023BB9',
|
||||
backgroundColor: '#96e3ff',
|
||||
fontFamily: 'Verdana',
|
||||
fontSize: 8,
|
||||
fontStyle: 'normal' as FontStyleType,
|
||||
fontWeight: 'normal' as FontWeightType,
|
||||
fontColor: '#000000',
|
||||
connectionStyle: LineType.THICK_CURVED,
|
||||
connectionColor: '#345780',
|
||||
shapeType: 'line' as TopicShapeType,
|
||||
outerBackgroundColor: '#F4B82D',
|
||||
outerBorderColor: '#F4B82D',
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
class PrismTheme extends DefaultTheme {
|
||||
constructor() {
|
||||
super(defaultStyles);
|
||||
}
|
||||
|
||||
getCanvasCssStyle(): string {
|
||||
return `position: relative;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
background-color: #f2f2f2;
|
||||
background-image: linear-gradient(#ebe9e7 1px, transparent 1px),
|
||||
linear-gradient(to right, #ebe9e7 1px, #f2f2f2 1px);
|
||||
background-size: 50px 50px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;`;
|
||||
}
|
||||
|
||||
getConnectionColor(topic: Topic): string {
|
||||
const model = topic.getModel();
|
||||
let result: string | undefined = model.getConnectionColor();
|
||||
|
||||
if (!result) {
|
||||
let colors: string[] = [];
|
||||
colors = colors.concat(this.resolve('connectionColor', topic) as string[] | string);
|
||||
|
||||
// if the element is an array, use topic order to decide color ..
|
||||
let order = topic.getOrder();
|
||||
order = order || 0;
|
||||
|
||||
const index = order % colors.length;
|
||||
result = colors[index];
|
||||
}
|
||||
return result!;
|
||||
}
|
||||
|
||||
getBorderColor(topic: Topic): string {
|
||||
const model = topic.getModel();
|
||||
let result = model.getBorderColor();
|
||||
|
||||
// If the the style is a line, the color is alward the connection one.
|
||||
|
||||
// If border color has not been defined, use the connection color for the border ...
|
||||
if (!result) {
|
||||
if (topic.getShapeType() === 'line') {
|
||||
result = 'none';
|
||||
} else {
|
||||
let colors: string[] = [];
|
||||
colors = colors.concat(this.resolve('borderColor', topic) as string[] | string);
|
||||
|
||||
// if the element is an array, use topic order to decide color ..
|
||||
let order = topic.getOrder();
|
||||
order = order || 0;
|
||||
|
||||
const index = order % colors.length;
|
||||
result = colors[index];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export default PrismTheme;
|
57
packages/mindplot/src/components/theme/Theme.ts
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright [2021] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { LineType } from '../ConnectionLine';
|
||||
import { FontStyleType } from '../FontStyleType';
|
||||
import { FontWeightType } from '../FontWeightType';
|
||||
import { TopicShapeType } from '../model/INodeModel';
|
||||
import Topic from '../Topic';
|
||||
|
||||
export type TopicType = 'CentralTopic' | 'MainTopic' | 'SubTopic' | 'IsolatedTopic';
|
||||
interface Theme {
|
||||
getText(topic: Topic): string;
|
||||
|
||||
getFontFamily(topic: Topic): string;
|
||||
|
||||
getFontSize(topic: Topic): number;
|
||||
|
||||
getFontStyle(topic: Topic): FontStyleType;
|
||||
|
||||
getFontWeight(topic: Topic): FontWeightType;
|
||||
|
||||
getFontColor(topic: Topic): string;
|
||||
|
||||
getCanvasCssStyle(): string;
|
||||
|
||||
getOuterBorderColor(topic: Topic): string;
|
||||
|
||||
getOuterBackgroundColor(topic: Topic, onFocus: boolean): string;
|
||||
|
||||
getBackgroundColor(topic: Topic): string;
|
||||
|
||||
getBorderColor(topic: Topic): string;
|
||||
|
||||
getInnerPadding(topic: Topic): number;
|
||||
|
||||
getShapeType(topic: Topic): TopicShapeType;
|
||||
|
||||
getConnectionType(topic: Topic): LineType;
|
||||
|
||||
getConnectionColor(topic: Topic): string;
|
||||
}
|
||||
export default Theme;
|
36
packages/mindplot/src/components/theme/ThemeFactory.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import NodeModel from '../model/NodeModel';
|
||||
import ClassicTheme from './ClassicTheme';
|
||||
import PrismTheme from './PrismTheme';
|
||||
import Theme from './Theme';
|
||||
|
||||
type ThemeId = 'prism' | 'classic';
|
||||
|
||||
class ThemeFactory {
|
||||
private static prismTheme = new PrismTheme();
|
||||
|
||||
private static classicTheme = new ClassicTheme();
|
||||
|
||||
static createById(id: ThemeId): Theme {
|
||||
let result: Theme;
|
||||
switch (id) {
|
||||
case 'classic':
|
||||
result = ThemeFactory.classicTheme;
|
||||
break;
|
||||
case 'prism':
|
||||
result = ThemeFactory.prismTheme;
|
||||
break;
|
||||
default: {
|
||||
const exhaustiveCheck: never = id;
|
||||
throw new Error(exhaustiveCheck);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static create(model: NodeModel): Theme {
|
||||
const mindmap = model.getMindmap();
|
||||
const theme = mindmap.getTheme();
|
||||
return ThemeFactory.createById(theme);
|
||||
}
|
||||
}
|
||||
export default ThemeFactory;
|
@ -35,7 +35,7 @@ class ArcLine extends ArcLine2d {
|
||||
let xOffset = x;
|
||||
if (this._targetTopic.isCentralTopic()) {
|
||||
const sourceX = this._sourceTopic.getPosition().x;
|
||||
xOffset = Math.sign(sourceX) * (this._targetTopic.getSize().width / 3);
|
||||
xOffset = Math.sign(sourceX) * 10;
|
||||
} else {
|
||||
xOffset = x + 3 * Math.sign(x);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class LineTopicShape extends StraightLine {
|
||||
private _size: SizeType | null;
|
||||
|
||||
constructor(topic: Topic, attributes?: StyleAttributes) {
|
||||
const stokeColor = topic.getConnectionColor();
|
||||
const stokeColor = topic.getBorderColor();
|
||||
super({ ...attributes, strokeColor: stokeColor });
|
||||
this._size = null;
|
||||
}
|
||||
|