mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-24 15:37:55 +01:00
Add storybook theme tests
This commit is contained in:
parent
c1d81cd074
commit
4fc015c6dc
11
packages/mindplot/cypress/e2e/connection.test.js
Normal file
11
packages/mindplot/cypress/e2e/connection.test.js
Normal file
@ -0,0 +1,11 @@
|
||||
context('Connection suite', () => {
|
||||
it('classic theme', () => {
|
||||
cy.visit('/iframe.html?args=&id=mindplot-connection--classic&viewMode=story');
|
||||
cy.matchImageSnapshot('connection-classic');
|
||||
});
|
||||
|
||||
it('classic prism', () => {
|
||||
cy.visit('/iframe.html?args=&id=mindplot-connection--prism&viewMode=story');
|
||||
cy.matchImageSnapshot('connection-prism');
|
||||
});
|
||||
});
|
@ -33,4 +33,8 @@ context('Topic suite', () => {
|
||||
cy.visit('/iframe.html?args=&id=mindplot-topic--shape-ellipse&viewMode=story');
|
||||
cy.matchImageSnapshot('topic-shape-ellipse');
|
||||
});
|
||||
});
|
||||
it('topic none line', () => {
|
||||
cy.visit('/iframe.html?args=&id=mindplot-topic--shape-none&viewMode=story');
|
||||
cy.matchImageSnapshot('topic-shape-none');
|
||||
});
|
||||
});
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -21,13 +21,14 @@ import { $assert } from '@wisemapping/core-js';
|
||||
import { Mindmap } from '..';
|
||||
import CommandContext from './CommandContext';
|
||||
import { PivotType } from './RelationshipControlPoints';
|
||||
import Events from './Events';
|
||||
import EventDispispatcher from './EventDispatcher';
|
||||
import NodeModel from './model/NodeModel';
|
||||
import RelationshipModel from './model/RelationshipModel';
|
||||
import Topic from './Topic';
|
||||
import PositionType from './PositionType';
|
||||
import EventBusType from './EventBusType';
|
||||
|
||||
abstract class ActionDispatcher extends Events {
|
||||
abstract class ActionDispatcher extends EventDispispatcher<EventBusType> {
|
||||
private static _instance: ActionDispatcher;
|
||||
|
||||
private _commandContext: CommandContext;
|
||||
|
@ -20,7 +20,7 @@ import $ from 'jquery';
|
||||
import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import Messages, { $msg } from './Messages';
|
||||
|
||||
import Events from './Events';
|
||||
import EventDispispatcher from './EventDispatcher';
|
||||
import StandaloneActionDispatcher from './StandaloneActionDispatcher';
|
||||
|
||||
import CommandContext from './CommandContext';
|
||||
@ -37,7 +37,7 @@ import DragManager from './DragManager';
|
||||
import RelationshipPivot from './RelationshipPivot';
|
||||
import Relationship from './Relationship';
|
||||
|
||||
import TopicEventDispatcher, { TopicEvent } from './TopicEventDispatcher';
|
||||
import TopicEventDispatcher from './TopicEventDispatcher';
|
||||
import TopicFactory from './TopicFactory';
|
||||
|
||||
import EventBus from './layout/EventBus';
|
||||
@ -62,8 +62,11 @@ import ImageExpoterFactory from './export/ImageExporterFactory';
|
||||
import PositionType from './PositionType';
|
||||
import ThemeType from './model/ThemeType';
|
||||
import ThemeFactory from './theme/ThemeFactory';
|
||||
import ChangeEvent from './layout/ChangeEvent';
|
||||
|
||||
class Designer extends Events {
|
||||
type DesignerEventType = 'modelUpdate' | 'onfocus' | 'onblur' | 'loadSuccess';
|
||||
|
||||
class Designer extends EventDispispatcher<DesignerEventType> {
|
||||
private _mindmap: Mindmap | null;
|
||||
|
||||
private _options: DesignerOptions;
|
||||
@ -159,14 +162,9 @@ class Designer extends Events {
|
||||
return this._actionDispatcher;
|
||||
}
|
||||
|
||||
addEvent(type: string, listener): Events {
|
||||
if (type === TopicEvent.EDIT || type === TopicEvent.CLICK) {
|
||||
const editor = TopicEventDispatcher.getInstance();
|
||||
editor.addEvent(type, listener);
|
||||
} else {
|
||||
super.addEvent(type, listener);
|
||||
}
|
||||
return this;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
addEvent(type: DesignerEventType, listener: (event: (args?: any) => void) => void): void {
|
||||
super.addEvent(type, listener);
|
||||
}
|
||||
|
||||
private _registerMouseEvents() {
|
||||
@ -619,7 +617,8 @@ class Designer extends Events {
|
||||
// Init layout manager ...
|
||||
const size = { width: 25, height: 25 };
|
||||
const layoutManager = new LayoutManager(mindmap.getCentralTopic().getId(), size);
|
||||
layoutManager.addEvent('change', (event) => {
|
||||
|
||||
layoutManager.addEvent('change', (event: ChangeEvent) => {
|
||||
const id = event.getId();
|
||||
const topic = this.getModel().findTopicById(id);
|
||||
if (topic) {
|
||||
@ -627,6 +626,7 @@ class Designer extends Events {
|
||||
topic.setOrder(event.getOrder());
|
||||
}
|
||||
});
|
||||
|
||||
this._eventBussDispatcher.setLayoutManager(layoutManager);
|
||||
|
||||
// Building node graph ...
|
||||
@ -652,6 +652,7 @@ class Designer extends Events {
|
||||
|
||||
// Enable workspace drag events ...
|
||||
this._canvas.registerEvents();
|
||||
|
||||
// Finally, sort the map ...
|
||||
EventBus.instance.fireEvent('forceLayout');
|
||||
this.fireEvent('loadSuccess');
|
||||
|
@ -18,12 +18,11 @@
|
||||
import { $assert } from '@wisemapping/core-js';
|
||||
import CentralTopic from './CentralTopic';
|
||||
import { DesignerOptions } from './DesignerOptionsBuilder';
|
||||
import Events from './Events';
|
||||
import Relationship from './Relationship';
|
||||
import Topic from './Topic';
|
||||
import { $notify } from './model/ToolbarNotifier';
|
||||
|
||||
class DesignerModel extends Events {
|
||||
class DesignerModel {
|
||||
private _zoom: number;
|
||||
|
||||
private _topics: Topic[];
|
||||
@ -31,7 +30,6 @@ class DesignerModel extends Events {
|
||||
private _relationships: Relationship[];
|
||||
|
||||
constructor(options: DesignerOptions) {
|
||||
super();
|
||||
this._zoom = options.zoom;
|
||||
this._topics = [];
|
||||
this._relationships = [];
|
||||
|
30
packages/mindplot/src/components/EventBusType.ts
Normal file
30
packages/mindplot/src/components/EventBusType.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export type EventBusType =
|
||||
| 'topicResize'
|
||||
| 'topicMoved'
|
||||
| 'forceLayout'
|
||||
| 'childShrinked'
|
||||
| 'topicConnected'
|
||||
| 'topicAdded'
|
||||
| 'topicRemoved'
|
||||
| 'topicDisconect'
|
||||
| 'modelUpdate';
|
||||
|
||||
export default EventBusType;
|
73
packages/mindplot/src/components/EventDispatcher.ts
Normal file
73
packages/mindplot/src/components/EventDispatcher.ts
Normal file
@ -0,0 +1,73 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
class EventDispispatcher<T> {
|
||||
private _handlerByType: Map<T, ((args?: any) => void)[]>;
|
||||
|
||||
constructor() {
|
||||
this._handlerByType = new Map();
|
||||
}
|
||||
|
||||
private static _normalizeEventName<K>(value: K): K {
|
||||
return String(value).replace(/^on([A-Z])/, (_full, first) => first.toLowerCase()) as K;
|
||||
}
|
||||
|
||||
addEvent(typeName: T, fn: (args?: any) => void, internal?: boolean): void {
|
||||
const type = EventDispispatcher._normalizeEventName(typeName);
|
||||
|
||||
let events = this._handlerByType.get(type);
|
||||
// Add function had not been added yet
|
||||
events = events || [];
|
||||
if (events && !events.includes(fn)) {
|
||||
events.push(fn);
|
||||
this._handlerByType.set(type, events);
|
||||
}
|
||||
|
||||
// Mark reference ...
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
fn.internal = Boolean(internal);
|
||||
}
|
||||
|
||||
fireEvent(typeName: T, arg?: any): void {
|
||||
const type = EventDispispatcher._normalizeEventName(typeName);
|
||||
const events = this._handlerByType.get(type);
|
||||
if (events) {
|
||||
const args: any = arg ? [arg] : [];
|
||||
events.forEach((fn) => {
|
||||
fn.apply(this, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeEvent(typeName: T, fn: (...args: any) => void): void {
|
||||
const type = EventDispispatcher._normalizeEventName(typeName);
|
||||
const events = this._handlerByType.get(type);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
if (events && !fn.internal) {
|
||||
const index = events.indexOf(fn);
|
||||
if (index !== -1) {
|
||||
events.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default EventDispispatcher;
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class Events {
|
||||
protected _handlerByType;
|
||||
|
||||
constructor() {
|
||||
this._handlerByType = {};
|
||||
}
|
||||
|
||||
static _normalizeEventName(string: string) {
|
||||
return string.replace(/^on([A-Z])/, (_full, first) => first.toLowerCase());
|
||||
}
|
||||
|
||||
addEvent(typeName: string, fn?, internal?: boolean): Events {
|
||||
const type = Events._normalizeEventName(typeName);
|
||||
|
||||
// Add function had not been added yet
|
||||
const funByType = this._handlerByType[type] ? this._handlerByType[type] : [];
|
||||
if (!funByType.includes(fn)) {
|
||||
funByType.push(fn);
|
||||
this._handlerByType[type] = funByType;
|
||||
}
|
||||
|
||||
// Mark reference ...
|
||||
fn.internal = Boolean(internal);
|
||||
return this;
|
||||
}
|
||||
|
||||
fireEvent(typeName: string, eventArgs?): Events {
|
||||
const type = Events._normalizeEventName(typeName);
|
||||
const events = this._handlerByType[type];
|
||||
if (!events) return this;
|
||||
|
||||
const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs];
|
||||
events.forEach((fn) => {
|
||||
// Execute our of the main thread...
|
||||
fn.apply(this, args);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
removeEvent(typeName: string, fn?): Events {
|
||||
const type = Events._normalizeEventName(typeName);
|
||||
const events = this._handlerByType[type];
|
||||
if (events && !fn.internal) {
|
||||
const index = events.indexOf(fn);
|
||||
if (index !== -1) events.splice(index, 1);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export default Events;
|
@ -20,11 +20,13 @@ import { FontStyle } from '@wisemapping/web2d/src/components/peer/svg/FontPeer';
|
||||
import $ from 'jquery';
|
||||
|
||||
import ActionDispatcher from './ActionDispatcher';
|
||||
import Events from './Events';
|
||||
import EventDispatcher from './EventDispatcher';
|
||||
import EventBus from './layout/EventBus';
|
||||
import Topic from './Topic';
|
||||
|
||||
class EditorComponent extends Events {
|
||||
type EditorEventType = 'input';
|
||||
|
||||
class EditorComponent extends EventDispatcher<EditorEventType> {
|
||||
private _topic: Topic;
|
||||
|
||||
private _oldText: string | undefined;
|
||||
|
@ -55,7 +55,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
|
||||
this._actionRunner = new DesignerActionRunner(commandContext, this);
|
||||
}
|
||||
|
||||
addTopics(models: NodeModel[], parentTopicsId: number[] | null) {
|
||||
addTopics(models: NodeModel[], parentTopicsId: number[] | null): void {
|
||||
const command = new AddTopicCommand(models, parentTopicsId);
|
||||
this.execute(command);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import EventBus from './layout/EventBus';
|
||||
import ShirinkConnector from './ShrinkConnector';
|
||||
import ActionDispatcher from './ActionDispatcher';
|
||||
|
||||
import TopicEventDispatcher, { TopicEvent } from './TopicEventDispatcher';
|
||||
import TopicEventDispatcher from './TopicEventDispatcher';
|
||||
import { TopicShapeType } from './model/INodeModel';
|
||||
import NodeModel from './model/NodeModel';
|
||||
import Relationship from './Relationship';
|
||||
@ -528,7 +528,7 @@ abstract class Topic extends NodeGraph {
|
||||
}
|
||||
|
||||
const eventDispatcher = me._getTopicEventDispatcher();
|
||||
eventDispatcher.process(TopicEvent.CLICK, me);
|
||||
eventDispatcher.process('clicknode', me);
|
||||
event.stopPropagation();
|
||||
});
|
||||
}
|
||||
@ -594,7 +594,7 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
getShrinkConnector(): ShirinkConnector | null {
|
||||
let result = this._connector;
|
||||
if (this._connector == null) {
|
||||
if (!this._connector) {
|
||||
this._connector = new ShirinkConnector(this);
|
||||
this._connector.setVisibility(false);
|
||||
result = this._connector;
|
||||
@ -693,11 +693,8 @@ abstract class Topic extends NodeGraph {
|
||||
* Point: references the center of the rect shape.!!!
|
||||
*/
|
||||
setPosition(point: PositionType): void {
|
||||
$assert(point, 'position can not be null');
|
||||
// allowed param reassign to avoid risks of existing code relying in this side-effect
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
point.x = Math.ceil(point.x);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
point.y = Math.ceil(point.y);
|
||||
|
||||
// Update model's position ...
|
||||
@ -721,7 +718,6 @@ abstract class Topic extends NodeGraph {
|
||||
this.invariant();
|
||||
}
|
||||
|
||||
/** */
|
||||
getOutgoingLine(): ConnectionLine | null {
|
||||
return this._outgoingLine;
|
||||
}
|
||||
@ -959,7 +955,7 @@ abstract class Topic extends NodeGraph {
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
connectTo(targetTopic: Topic, workspace: Canvas): void {
|
||||
connectTo(targetTopic: Topic, canvas: Canvas): void {
|
||||
// Connect Graphical Nodes ...
|
||||
targetTopic.append(this);
|
||||
this._parent = targetTopic;
|
||||
@ -971,10 +967,10 @@ abstract class Topic extends NodeGraph {
|
||||
|
||||
// Create a connection line ...
|
||||
const outgoingLine = this.createConnectionLine(targetTopic);
|
||||
outgoingLine.setVisibility(false);
|
||||
// outgoingLine.setVisibility(false);
|
||||
|
||||
this._outgoingLine = outgoingLine;
|
||||
workspace.append(outgoingLine);
|
||||
canvas.append(outgoingLine);
|
||||
|
||||
// Update figure is necessary.
|
||||
this.updateTopicShape(targetTopic);
|
||||
|
@ -15,20 +15,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import Events from './Events';
|
||||
import EventDispispatcher from './EventDispatcher';
|
||||
import Topic from './Topic';
|
||||
import MultitTextEditor from './MultilineTextEditor';
|
||||
|
||||
const TopicEvent = {
|
||||
EDIT: 'editnode',
|
||||
CLICK: 'clicknode',
|
||||
};
|
||||
type TopicEventType = 'editnode' | 'clicknode';
|
||||
|
||||
class TopicEventDispatcher extends Events {
|
||||
class TopicEventDispatcher extends EventDispispatcher<TopicEventType> {
|
||||
private _readOnly: boolean;
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
static _instance: TopicEventDispatcher;
|
||||
private static _instance: TopicEventDispatcher;
|
||||
|
||||
constructor(readOnly: boolean) {
|
||||
super();
|
||||
@ -43,10 +40,10 @@ class TopicEventDispatcher extends Events {
|
||||
}
|
||||
|
||||
show(topic: Topic, textOverwrite?: string): void {
|
||||
this.process(TopicEvent.EDIT, topic, textOverwrite);
|
||||
this.process('editnode', topic, textOverwrite);
|
||||
}
|
||||
|
||||
process(eventType: string, topic: Topic, textOverwrite?: string): void {
|
||||
process(eventType: TopicEventType, topic: Topic, textOverwrite?: string): void {
|
||||
// Close all previous open editor ....
|
||||
const editor = MultitTextEditor.getInstance();
|
||||
if (editor.isActive()) {
|
||||
@ -55,7 +52,7 @@ class TopicEventDispatcher extends Events {
|
||||
|
||||
// Open the new editor ...
|
||||
const model = topic.getModel();
|
||||
if (!this._readOnly && eventType === TopicEvent.EDIT) {
|
||||
if (!this._readOnly && eventType === 'editnode') {
|
||||
editor.show(topic, textOverwrite);
|
||||
} else {
|
||||
this.fireEvent(eventType, { model, readOnly: this._readOnly });
|
||||
@ -66,8 +63,13 @@ class TopicEventDispatcher extends Events {
|
||||
return MultitTextEditor.getInstance().isActive();
|
||||
}
|
||||
|
||||
static configure(readOnly: boolean): void {
|
||||
static configure(readOnly: boolean): TopicEventDispatcher {
|
||||
if (this._instance) {
|
||||
throw new Error('events already initialized');
|
||||
}
|
||||
|
||||
this._instance = new TopicEventDispatcher(readOnly);
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
static getInstance(): TopicEventDispatcher {
|
||||
@ -77,6 +79,4 @@ class TopicEventDispatcher extends Events {
|
||||
return this._instance;
|
||||
}
|
||||
}
|
||||
|
||||
export { TopicEvent };
|
||||
export default TopicEventDispatcher;
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/*
|
||||
* Copyright [2021] [wisemapping]
|
||||
*
|
||||
@ -15,18 +16,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import Events from '../Events';
|
||||
import EventDispispatcher from '../EventDispatcher';
|
||||
import { EventBusType } from '../EventBusType';
|
||||
|
||||
export type EventType =
|
||||
| 'topicResize'
|
||||
| 'topicMoved'
|
||||
| 'childShrinked'
|
||||
| 'topicConnected'
|
||||
| 'topicAdded'
|
||||
| 'topicRemoved'
|
||||
| 'forceLayout'
|
||||
| 'topicDisconect';
|
||||
class EventBus extends Events {
|
||||
class EventBus extends EventDispispatcher<EventBusType> {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
static _instance: EventBus = new EventBus();
|
||||
|
||||
@ -34,11 +27,11 @@ class EventBus extends Events {
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
fireEvent(type: EventType, eventArgs?: unknown[] | unknown): Events {
|
||||
return super.fireEvent(type, eventArgs);
|
||||
fireEvent(type: EventBusType, arg?: any): void {
|
||||
return super.fireEvent(type, arg);
|
||||
}
|
||||
|
||||
addEvent(type: EventType, fn?, internal?: boolean): Events {
|
||||
addEvent(type: EventBusType, fn: (arg?: any) => void, internal?: boolean): void {
|
||||
return super.addEvent(type, fn, internal);
|
||||
}
|
||||
}
|
||||
|
@ -45,15 +45,15 @@ class EventBusDispatcher {
|
||||
}
|
||||
|
||||
private _topicResizeEvent(args: { node: Topic; size: SizeType }) {
|
||||
this._layoutManager!.updateNodeSize(args.node.getId(), args.size);
|
||||
this.getLayoutManager().updateNodeSize(args.node.getId(), args.size);
|
||||
}
|
||||
|
||||
private _topicMoved(args: { node: Topic; position: PositionType }) {
|
||||
this._layoutManager!.moveNode(args.node.getId(), args.position);
|
||||
this.getLayoutManager().moveNode(args.node.getId(), args.position);
|
||||
}
|
||||
|
||||
private _topicDisconect(node: Topic) {
|
||||
this._layoutManager!.disconnectNode(node.getId());
|
||||
this.getLayoutManager().disconnectNode(node.getId());
|
||||
}
|
||||
|
||||
private _topicConnected(args: { parentNode: Topic; childNode: Topic }) {
|
||||
@ -64,28 +64,31 @@ class EventBusDispatcher {
|
||||
);
|
||||
}
|
||||
|
||||
getLayoutManager(): LayoutManager {
|
||||
if (!this._layoutManager) {
|
||||
throw new Error('Layout not initialized');
|
||||
}
|
||||
return this._layoutManager;
|
||||
}
|
||||
|
||||
private _childShrinked(node: Topic) {
|
||||
this._layoutManager!.updateShrinkState(node.getId(), node.areChildrenShrunken());
|
||||
this.getLayoutManager().updateShrinkState(node.getId(), node.areChildrenShrunken());
|
||||
}
|
||||
|
||||
private _topicAdded(node: Topic) {
|
||||
// Central topic must not be added twice ...
|
||||
if (node.getId() !== 0) {
|
||||
this._layoutManager!.addNode(node.getId(), { width: 10, height: 10 }, node.getPosition());
|
||||
this._layoutManager!.updateShrinkState(node.getId(), node.areChildrenShrunken());
|
||||
this.getLayoutManager().addNode(node.getId(), { width: 10, height: 10 }, node.getPosition());
|
||||
this.getLayoutManager().updateShrinkState(node.getId(), node.areChildrenShrunken());
|
||||
}
|
||||
}
|
||||
|
||||
private _topicRemoved(node: Topic) {
|
||||
this._layoutManager!.removeNode(node.getId());
|
||||
this.getLayoutManager().removeNode(node.getId());
|
||||
}
|
||||
|
||||
private _forceLayout() {
|
||||
this._layoutManager!.layout(true);
|
||||
}
|
||||
|
||||
getLayoutManager(): LayoutManager {
|
||||
return this._layoutManager!;
|
||||
private _forceLayout(): void {
|
||||
this.getLayoutManager().layout(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
20
packages/mindplot/src/components/layout/LayoutEventType.ts
Normal file
20
packages/mindplot/src/components/layout/LayoutEventType.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 LayoutEventType = 'change' | 'forceLayout';
|
||||
|
||||
export default LayoutEventType;
|
@ -16,15 +16,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import Events from '../Events';
|
||||
import EventDispispatcher from '../EventDispatcher';
|
||||
import RootedTreeSet from './RootedTreeSet';
|
||||
import OriginalLayout from './OriginalLayout';
|
||||
import ChangeEvent from './ChangeEvent';
|
||||
import SizeType from '../SizeType';
|
||||
import Node from './Node';
|
||||
import PositionType from '../PositionType';
|
||||
import LayoutEventType from './LayoutEventType';
|
||||
|
||||
class LayoutManager extends Events {
|
||||
class LayoutManager extends EventDispispatcher<LayoutEventType> {
|
||||
private _treeSet: RootedTreeSet;
|
||||
|
||||
private _layout: OriginalLayout;
|
||||
|
@ -15,6 +15,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
type ThemeType = 'classic' | 'prism';
|
||||
type ThemeType = 'classic' | 'prism' | 'dark-prism';
|
||||
|
||||
export default ThemeType;
|
||||
|
@ -1,11 +1,10 @@
|
||||
import NodeModel from '../model/NodeModel';
|
||||
import ThemeType from '../model/ThemeType';
|
||||
import ClassicTheme from './ClassicTheme';
|
||||
import DarkPrismTheme from './DarkPrismTheme';
|
||||
import PrismTheme from './PrismTheme';
|
||||
import Theme from './Theme';
|
||||
|
||||
type ThemeId = 'prism' | 'classic' | 'dark-prism';
|
||||
|
||||
class ThemeFactory {
|
||||
private static prismTheme = new PrismTheme();
|
||||
|
||||
@ -13,7 +12,7 @@ class ThemeFactory {
|
||||
|
||||
private static classicTheme = new ClassicTheme();
|
||||
|
||||
static createById(id: ThemeId): Theme {
|
||||
static createById(id: ThemeType): Theme {
|
||||
let result: Theme;
|
||||
switch (id) {
|
||||
case 'classic':
|
||||
|
@ -0,0 +1,30 @@
|
||||
import { Story, Meta } from '@storybook/html';
|
||||
import createConnection, { TopicArgs } from './Connection';
|
||||
|
||||
export default {
|
||||
title: 'Mindplot/Connection',
|
||||
// More on argTypes: https://storybook.js.org/docs/html/api/argtypes
|
||||
argTypes: {
|
||||
shapeType: {
|
||||
options: ['none', 'rectangle', 'rounded rectangle', 'elipse', 'line'],
|
||||
control: { type: 'select' },
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
const Template: Story<TopicArgs> = (args: TopicArgs) => createConnection(args);
|
||||
|
||||
export const Classic = Template.bind({});
|
||||
Classic.args = {
|
||||
theme: 'classic',
|
||||
};
|
||||
|
||||
export const Prism = Template.bind({});
|
||||
Prism.args = {
|
||||
theme: 'prism',
|
||||
};
|
||||
|
||||
export const DarkPrism = Template.bind({});
|
||||
DarkPrism.args = {
|
||||
theme: 'dark-prism',
|
||||
};
|
136
packages/mindplot/storybook/src/stories/Connection.ts
Normal file
136
packages/mindplot/storybook/src/stories/Connection.ts
Normal file
@ -0,0 +1,136 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
import { Mindmap, Topic } from '../../../src';
|
||||
import NodeModel from '../../../src/components/model/NodeModel';
|
||||
import CentralTopic from '../../../src/components/CentralTopic';
|
||||
import Canvas from '../../../src/components/Canvas';
|
||||
import ScreenManager from '../../../src/components/ScreenManager';
|
||||
import TopicEventDispatcher from '../../../src/components/TopicEventDispatcher';
|
||||
import ThemeType from '../../../src/components/model/ThemeType';
|
||||
import MainTopic from '../../../src/components/MainTopic';
|
||||
import EventBusDispatcher from '../../../src/components/layout/EventBusDispatcher';
|
||||
import LayoutManager from '../../../src/components/layout/LayoutManager';
|
||||
import ChangeEvent from '../../../src/components/layout/ChangeEvent';
|
||||
import EventBus from '../../../src/components/layout/EventBus';
|
||||
|
||||
const registerRefreshHook = (topics: Topic[]) => {
|
||||
// Trigger a redraw after the node is added ...
|
||||
if (globalThis.observer) {
|
||||
globalThis.observer.disconnect();
|
||||
}
|
||||
|
||||
globalThis.observer = new MutationObserver(() => {
|
||||
// Relayout...
|
||||
topics.forEach((t) => t.redraw());
|
||||
EventBus.instance.fireEvent('forceLayout');
|
||||
});
|
||||
globalThis.observer.observe(document.getElementById('root')!, { childList: true });
|
||||
};
|
||||
|
||||
export type TopicArgs = {
|
||||
readOnly?: boolean;
|
||||
theme?: ThemeType;
|
||||
};
|
||||
|
||||
const createConnection = ({ theme = undefined, readOnly = true }: TopicArgs) => {
|
||||
// Build basic container ...
|
||||
const divElem = document.createElement('div');
|
||||
const jqueryDiv = $(divElem);
|
||||
jqueryDiv.css({
|
||||
height: '600px',
|
||||
width: '800px',
|
||||
backgroundColor: 'gray',
|
||||
});
|
||||
|
||||
// Initialize designer helpers ...
|
||||
const screenManager = new ScreenManager(divElem);
|
||||
const canvas = new Canvas(screenManager, 0.7, readOnly);
|
||||
TopicEventDispatcher.configure(readOnly);
|
||||
|
||||
// Register event propagation ..
|
||||
const mindmap = new Mindmap();
|
||||
const central = new NodeModel('CentralTopic', mindmap);
|
||||
central.setText('Central Topic');
|
||||
mindmap.addBranch(central);
|
||||
|
||||
// Add Children ...
|
||||
const child1 = new NodeModel('MainTopic', mindmap);
|
||||
child1.setOrder(0);
|
||||
child1.setText('This is child one !\nwith other line');
|
||||
child1.setPosition(100, 100);
|
||||
|
||||
const child2 = new NodeModel('MainTopic', mindmap);
|
||||
child2.setOrder(1);
|
||||
child2.setPosition(100, -100);
|
||||
|
||||
const child3 = new NodeModel('MainTopic', mindmap);
|
||||
child3.setOrder(0);
|
||||
child3.setPosition(-100, 100);
|
||||
|
||||
const child4 = new NodeModel('MainTopic', mindmap);
|
||||
child4.setOrder(1);
|
||||
child4.setPosition(-100, -100);
|
||||
|
||||
const subchild1 = new NodeModel('MainTopic', mindmap);
|
||||
subchild1.setOrder(0);
|
||||
subchild1.setPosition(300, 80);
|
||||
|
||||
const subchild2 = new NodeModel('MainTopic', mindmap);
|
||||
subchild2.setOrder(1);
|
||||
subchild2.setPosition(300, 120);
|
||||
|
||||
// Theme ...
|
||||
if (theme) {
|
||||
mindmap.setTheme(theme);
|
||||
}
|
||||
|
||||
// Create and add to canvas..
|
||||
const centralTopic = new CentralTopic(central, { readOnly });
|
||||
|
||||
const child1Topic = new MainTopic(child1, { readOnly });
|
||||
const child2Topic = new MainTopic(child2, { readOnly });
|
||||
const child3Topic = new MainTopic(child3, { readOnly });
|
||||
const child4Topic = new MainTopic(child4, { readOnly });
|
||||
const subchild1Topic = new MainTopic(subchild1, { readOnly });
|
||||
const subchild2Topic = new MainTopic(subchild2, { readOnly });
|
||||
const topics = [
|
||||
child1Topic,
|
||||
child2Topic,
|
||||
child3Topic,
|
||||
child4Topic,
|
||||
centralTopic,
|
||||
subchild1Topic,
|
||||
subchild2Topic,
|
||||
];
|
||||
|
||||
// Configure event dispatcher ...
|
||||
const dispatcher = new EventBusDispatcher();
|
||||
const size = { width: 25, height: 25 };
|
||||
const layoutManager = new LayoutManager(mindmap.getCentralTopic().getId(), size);
|
||||
dispatcher.setLayoutManager(layoutManager);
|
||||
layoutManager.addEvent('change', (event: ChangeEvent) => {
|
||||
const id = event.getId();
|
||||
const topic = topics.filter((t) => t.getModel().getId() === id)[0];
|
||||
|
||||
topic.setPosition(event.getPosition());
|
||||
topic.setOrder(event.getOrder());
|
||||
});
|
||||
|
||||
// Add to canvas ...
|
||||
topics.forEach((t) => canvas.append(t));
|
||||
|
||||
// Connect nodes ...
|
||||
child1Topic.connectTo(centralTopic, canvas);
|
||||
child2Topic.connectTo(centralTopic, canvas);
|
||||
child3Topic.connectTo(centralTopic, canvas);
|
||||
child4Topic.connectTo(centralTopic, canvas);
|
||||
subchild1Topic.connectTo(child1Topic, canvas);
|
||||
subchild2Topic.connectTo(child1Topic, canvas);
|
||||
|
||||
// Register refresh hook ..
|
||||
registerRefreshHook(topics);
|
||||
|
||||
return divElem;
|
||||
};
|
||||
|
||||
export default createConnection;
|
@ -21,6 +21,7 @@ export default {
|
||||
noteText: { control: 'text' },
|
||||
linkText: { control: 'text' },
|
||||
eicon: { control: 'multi-select', options: ['❤️', '🌈', '🖇️'] },
|
||||
theme: { control: 'select', options: ['classic', 'prism', 'dark-prism'] },
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
@ -83,3 +84,19 @@ ShapeNone.args = {
|
||||
eicon: ['🌈'],
|
||||
shapeType: 'none',
|
||||
};
|
||||
|
||||
export const ThemeClassic = Template.bind({});
|
||||
ThemeClassic.args = {
|
||||
text: 'Theme Classic',
|
||||
eicon: ['🌈'],
|
||||
shapeType: 'none',
|
||||
theme: 'classic',
|
||||
};
|
||||
|
||||
export const ThemePrime = Template.bind({});
|
||||
ThemePrime.args = {
|
||||
text: 'Theme Prime',
|
||||
eicon: ['🌈'],
|
||||
shapeType: 'none',
|
||||
theme: 'prism',
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ import ScreenManager from '../../../src/components/ScreenManager';
|
||||
import EmojiIconModel from '../../../src/components/model/EmojiIconModel';
|
||||
import TopicEventDispatcher from '../../../src/components/TopicEventDispatcher';
|
||||
import { TopicShapeType } from '../../../src/components/model/INodeModel';
|
||||
import ThemeType from '../../../src/components/model/ThemeType';
|
||||
|
||||
const registerRefreshHook = (topic: Topic) => {
|
||||
// Trigger a redraw after the node is added ...
|
||||
@ -34,6 +35,7 @@ export type TopicArgs = {
|
||||
noteText?: string;
|
||||
linkText?: string;
|
||||
eicon?: string[];
|
||||
theme?: ThemeType;
|
||||
};
|
||||
|
||||
const createTopic = ({
|
||||
@ -47,6 +49,7 @@ const createTopic = ({
|
||||
noteText = undefined,
|
||||
linkText = undefined,
|
||||
eicon = undefined,
|
||||
theme = undefined,
|
||||
readOnly = true,
|
||||
}: TopicArgs) => {
|
||||
// Build basic container ...
|
||||
@ -92,6 +95,11 @@ const createTopic = ({
|
||||
});
|
||||
}
|
||||
|
||||
// Theme ...
|
||||
if (theme) {
|
||||
mindmap.setTheme(theme);
|
||||
}
|
||||
|
||||
// Create topic UI element ...
|
||||
mindmap.addBranch(model);
|
||||
const centralTopic = new CentralTopic(model, { readOnly });
|
||||
|
Loading…
Reference in New Issue
Block a user