mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-22 14:47:56 +01:00
Add center position action.
Improve screenmanager positioning Change several clasess to typescript
This commit is contained in:
parent
1bebfa3dff
commit
cdd044c41d
@ -32,6 +32,7 @@
|
||||
},
|
||||
"private": false,
|
||||
"dependencies": {
|
||||
"@types/jquery": "^3.5.11",
|
||||
"@wisemapping/core-js": "^0.4.0",
|
||||
"@wisemapping/web2d": "^0.4.0",
|
||||
"jest": "^27.4.5",
|
||||
|
1
packages/mindplot/src/components/.gitignore
vendored
1
packages/mindplot/src/components/.gitignore
vendored
@ -1 +0,0 @@
|
||||
MessageBundle_*
|
@ -54,8 +54,9 @@ import { Mindmap } from '..';
|
||||
import NodeModel from './model/NodeModel';
|
||||
import Topic from './Topic';
|
||||
import Point from '@wisemapping/web2d';
|
||||
import { DesignerOptions } from './DesignerOptions';
|
||||
import { DesignerOptions } from './DesignerOptionsBuilder';
|
||||
import MainTopic from './MainTopic';
|
||||
import DragTopic from './DragTopic';
|
||||
|
||||
class Designer extends Events {
|
||||
private _mindmap: Mindmap;
|
||||
@ -69,7 +70,7 @@ class Designer extends Events {
|
||||
private _clipboard: any[];
|
||||
private _cleanScreen: any;
|
||||
|
||||
constructor(options: DesignerOptions, divElement) {
|
||||
constructor(options: DesignerOptions, divElement:JQuery) {
|
||||
$assert(options, 'options must be defined');
|
||||
$assert(options.zoom, 'zoom must be defined');
|
||||
$assert(options.size, 'size must be defined');
|
||||
@ -166,12 +167,12 @@ class Designer extends Events {
|
||||
});
|
||||
|
||||
// Deselect on click ...
|
||||
screenManager.addEvent('click', (event) => {
|
||||
screenManager.addEvent('click', (event:UIEvent) => {
|
||||
me.onObjectFocusEvent(null, event);
|
||||
});
|
||||
|
||||
// Create nodes on double click...
|
||||
screenManager.addEvent('dblclick', (event) => {
|
||||
screenManager.addEvent('dblclick', (event:MouseEvent) => {
|
||||
if (workspace.isWorkspaceEventsEnabled()) {
|
||||
const mousePos = screenManager.getWorkspaceMousePosition(event);
|
||||
const centralTopic = me.getModel().getCentralTopic();
|
||||
@ -181,13 +182,7 @@ class Designer extends Events {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {mindplot.Workspace} workspace
|
||||
* @return {mindplot.DragManager} the new dragManager for the workspace with events
|
||||
* registered
|
||||
*/
|
||||
_buildDragManager(workspace: Workspace) {
|
||||
private _buildDragManager(workspace: Workspace):DragManager {
|
||||
const designerModel = this.getModel();
|
||||
const dragConnector = new DragConnector(designerModel, this._workspace);
|
||||
const dragManager = new DragManager(workspace, this._eventBussDispatcher);
|
||||
@ -198,7 +193,7 @@ class Designer extends Events {
|
||||
topics.forEach((topic) => topic.setMouseEventsEnabled(false));
|
||||
});
|
||||
|
||||
dragManager.addEvent('dragging', (event, dragTopic) => {
|
||||
dragManager.addEvent('dragging', (event:MouseEvent, dragTopic:DragTopic) => {
|
||||
dragTopic.updateFreeLayout(event);
|
||||
if (!dragTopic.isFreeLayoutOn(event)) {
|
||||
// The node is being drag. Is the connection still valid ?
|
||||
@ -210,7 +205,7 @@ class Designer extends Events {
|
||||
}
|
||||
});
|
||||
|
||||
dragManager.addEvent('enddragging', (event, dragTopic) => {
|
||||
dragManager.addEvent('enddragging', (event:MouseEvent, dragTopic:DragTopic) => {
|
||||
topics.forEach((topic) => topic.setMouseEventsEnabled(true));
|
||||
dragTopic.applyChanges(workspace);
|
||||
});
|
||||
@ -218,11 +213,7 @@ class Designer extends Events {
|
||||
return dragManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{width:Number, height:Number}} size
|
||||
* sets width and height of the workspace
|
||||
*/
|
||||
setViewPort(size: { height: number, width: number }) {
|
||||
private setViewPort(size: { height: number, width: number }):void {
|
||||
this._workspace.setViewPort(size);
|
||||
const model = this.getModel();
|
||||
this._workspace.setZoom(model.getZoom(), true);
|
||||
@ -325,10 +316,6 @@ class Designer extends Events {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the zoom of the map
|
||||
* @param {Number} zoom number between 0.3 and 1.9
|
||||
*/
|
||||
setZoom(zoom: number): void {
|
||||
if (zoom > 1.9 || zoom < 0.3) {
|
||||
$notify($msg('ZOOM_IN_ERROR'));
|
||||
@ -338,6 +325,11 @@ class Designer extends Events {
|
||||
this._workspace.setZoom(zoom);
|
||||
}
|
||||
|
||||
setZoomToFit(): void {
|
||||
this.getModel().setZoom(1);
|
||||
this._workspace.setZoom(1,true);
|
||||
}
|
||||
|
||||
zoomOut(factor: number = 1.2) {
|
||||
const model = this.getModel();
|
||||
const scale = model.getZoom() * factor;
|
||||
@ -374,11 +366,7 @@ class Designer extends Events {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Number=} factor
|
||||
* zoom in by the given factor, or 1.2, if undefined
|
||||
*/
|
||||
zoomIn(factor: number = 1.2) {
|
||||
zoomIn(factor: number = 1.2): void {
|
||||
const model = this.getModel();
|
||||
const scale = model.getZoom() / factor;
|
||||
|
||||
@ -390,7 +378,6 @@ class Designer extends Events {
|
||||
}
|
||||
}
|
||||
|
||||
/** copy selected topics to a private clipboard */
|
||||
copyToClipboard(): void {
|
||||
let topics = this.getModel().filterSelectedTopics();
|
||||
if (topics.length <= 0) {
|
||||
@ -415,7 +402,6 @@ class Designer extends Events {
|
||||
$notify($msg('SELECTION_COPIED_TO_CLIPBOARD'));
|
||||
}
|
||||
|
||||
/** paste clipboard contents to the mindmap */
|
||||
pasteClipboard(): void {
|
||||
if (this._clipboard.length === 0) {
|
||||
$notify($msg('CLIPBOARD_IS_EMPTY'));
|
||||
@ -429,8 +415,7 @@ class Designer extends Events {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
/** collapse the subtree of the selected topic */
|
||||
shrinkSelectedBranch() {
|
||||
shrinkSelectedBranch(): void {
|
||||
const nodes = this.getModel().filterSelectedTopics();
|
||||
if (nodes.length <= 0 || nodes.length !== 1) {
|
||||
// If there are more than one node selected,
|
||||
@ -445,7 +430,7 @@ class Designer extends Events {
|
||||
}
|
||||
|
||||
/** create a NodeModel for the selected node's child and add it via the ActionDispatcher */
|
||||
createChildForSelectedNode() {
|
||||
createChildForSelectedNode():void {
|
||||
const nodes = this.getModel().filterSelectedTopics();
|
||||
if (nodes.length <= 0) {
|
||||
// If there are more than one node selected,
|
||||
@ -467,10 +452,7 @@ class Designer extends Events {
|
||||
this._actionDispatcher.addTopics([childModel], [parentTopicId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_copyNodeProps(sourceModel: NodeModel, targetModel: NodeModel) {
|
||||
private _copyNodeProps(sourceModel: NodeModel, targetModel: NodeModel) {
|
||||
// I don't copy the font size if the target is the source is the central topic.
|
||||
if (sourceModel.getType() !== 'CentralTopic') {
|
||||
const fontSize = sourceModel.getFontSize();
|
||||
@ -515,13 +497,7 @@ class Designer extends Events {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Topic} topic the parent topic of the child to create the NodeModel for
|
||||
* @param {Point} mousePos the mouse position
|
||||
* @return {NodeModel} the node model for the new child
|
||||
*/
|
||||
_createChildModel(topic: Topic, mousePos: Point = null): NodeModel {
|
||||
private _createChildModel(topic: Topic, mousePos: Point = null): NodeModel {
|
||||
// Create a new node ...
|
||||
const parentModel = topic.getModel();
|
||||
const mindmap = parentModel.getMindmap();
|
||||
@ -554,11 +530,7 @@ class Designer extends Events {
|
||||
topic.fireEvent('mousedown', event);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a sibling or child node of the selected node, if the selected node is the
|
||||
* central topic
|
||||
*/
|
||||
createSiblingForSelectedNode() {
|
||||
createSiblingForSelectedNode():void {
|
||||
const nodes = this.getModel().filterSelectedTopics();
|
||||
if (nodes.length <= 0) {
|
||||
// If there are no nodes selected,
|
||||
@ -591,12 +563,7 @@ class Designer extends Events {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {mindplot.Topic} topic the topic to create the sibling to
|
||||
* @return {mindplot.NodeModel} the node model of the sibling
|
||||
*/
|
||||
_createSiblingModel(topic: Topic) {
|
||||
private _createSiblingModel(topic: Topic):NodeModel {
|
||||
let result = null;
|
||||
let model = null;
|
||||
const parentTopic = topic.getOutgoingConnectedTopic();
|
||||
@ -617,10 +584,7 @@ class Designer extends Events {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Event} event
|
||||
*/
|
||||
showRelPivot(event) {
|
||||
showRelPivot(event):void {
|
||||
const nodes = this.getModel().filterSelectedTopics();
|
||||
if (nodes.length <= 0) {
|
||||
// This could not happen ...
|
||||
@ -761,7 +725,7 @@ class Designer extends Events {
|
||||
* deletes the relationship from the linked topics, DesignerModel, Workspace and Mindmap
|
||||
* @param {mindplot.Relationship} rel the relationship to delete
|
||||
*/
|
||||
deleteRelationship(rel) {
|
||||
deleteRelationship(rel: Relationship) {
|
||||
const sourceTopic = rel.getSourceTopic();
|
||||
sourceTopic.deleteRelationship(rel);
|
||||
|
||||
|
@ -22,29 +22,35 @@ import Designer from './Designer';
|
||||
import Menu from './widget/Menu';
|
||||
import { $notifyModal } from './widget/ModalDialogNotifier';
|
||||
import { $msg } from './Messages';
|
||||
import { DesignerOptions } from './DesignerOptionsBuilder';
|
||||
|
||||
let designer = null;
|
||||
|
||||
export function buildDesigner(options) {
|
||||
export function buildDesigner(options: DesignerOptions): Designer {
|
||||
const divContainer = $(`#${options.container}`);
|
||||
$assert(divContainer, 'container could not be null');
|
||||
|
||||
// Register load events ...
|
||||
designer = new Designer(options, divContainer);
|
||||
designer.addEvent('loadSuccess', () => {
|
||||
// @ts-ignore
|
||||
window.mindmapLoadReady = true;
|
||||
console.log('Map loadded successfully');
|
||||
});
|
||||
|
||||
const onerrorFn = (message, url, lineNo) => {
|
||||
const onerrorFn = (message:string, url, lineNo) => {
|
||||
// Close loading dialog ...
|
||||
// @ts-ignore
|
||||
if (window.waitDialog) {
|
||||
// @ts-ignore
|
||||
window.waitDialog.close();
|
||||
// @ts-ignore
|
||||
window.waitDialog = null;
|
||||
}
|
||||
|
||||
// Open error dialog only in case of mindmap loading errors. The rest of the error are reported but not display the dialog.
|
||||
// Remove this in the near future.
|
||||
// @ts-ignore
|
||||
if (!window.mindmapLoadReady) {
|
||||
$notifyModal($msg('UNEXPECTED_ERROR_LOADING'));
|
||||
}
|
||||
@ -58,7 +64,7 @@ export function buildDesigner(options) {
|
||||
|
||||
// Register toolbar event ...
|
||||
if ($('#toolbar').length) {
|
||||
const menu = new Menu(designer, 'toolbar', options.mapId, '');
|
||||
const menu = new Menu(designer, 'toolbar', options.mapId);
|
||||
|
||||
// If a node has focus, focus can be move to another node using the keys.
|
||||
designer._cleanScreen = function _cleanScreen() {
|
||||
@ -69,39 +75,3 @@ export function buildDesigner(options) {
|
||||
return designer;
|
||||
}
|
||||
|
||||
export function buildOptions(options) {
|
||||
$assert(options.persistenceManager, 'persistence must be defined');
|
||||
|
||||
// Set workspace screen size as default. In this way, resize issues are solved.
|
||||
const containerSize = {
|
||||
height: Number.parseInt(window.screen.height, 10),
|
||||
width: Number.parseInt(window.screen.width, 10),
|
||||
};
|
||||
|
||||
const viewPort = {
|
||||
height: Number.parseInt(window.innerHeight, 10),
|
||||
width: Number.parseInt(window.innerWidth, 10),
|
||||
};
|
||||
|
||||
const defaultOptions = {
|
||||
readOnly: false,
|
||||
zoom: 0.85,
|
||||
saveOnLoad: true,
|
||||
size: containerSize,
|
||||
viewPort,
|
||||
container: 'mindplot',
|
||||
locale: 'en',
|
||||
};
|
||||
|
||||
return { ...defaultOptions, ...options };
|
||||
}
|
||||
|
||||
export async function loadOptions(jsonConf, options) {
|
||||
const result = await $.ajax({
|
||||
url: jsonConf,
|
||||
dataType: 'json',
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
return { ...result, ...buildOptions(options) };
|
||||
}
|
@ -16,7 +16,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import { DesignerOptions } from './DesignerOptions';
|
||||
import CentralTopic from './CentralTopic';
|
||||
import { DesignerOptions } from './DesignerOptionsBuilder';
|
||||
import Events from './Events';
|
||||
import Relationship from './Relationship';
|
||||
import Topic from './Topic';
|
||||
@ -34,30 +35,25 @@ class DesignerModel extends Events {
|
||||
this._relationships = [];
|
||||
}
|
||||
|
||||
/** @return {Number} zoom between 0.3 (largest text) and 1.9 */
|
||||
getZoom() {
|
||||
getZoom():number {
|
||||
return this._zoom;
|
||||
}
|
||||
|
||||
/** @param {Number} zoom number between 0.3 and 1.9 to set the zoom to */
|
||||
setZoom(zoom: number) {
|
||||
setZoom(zoom: number):void {
|
||||
this._zoom = zoom;
|
||||
}
|
||||
|
||||
/** @return {@link mindplot.Topic[]} all topics */
|
||||
getTopics(): Topic[] {
|
||||
return this._topics;
|
||||
}
|
||||
|
||||
/** @return {mindplot.Relationship[]} all relationships */
|
||||
getRelationships(): Relationship[] {
|
||||
return this._relationships;
|
||||
}
|
||||
|
||||
/** @return {mindplot.CentralTopic} the central topic */
|
||||
getCentralTopic(): Topic {
|
||||
getCentralTopic(): CentralTopic {
|
||||
const topics = this.getTopics();
|
||||
return topics[0];
|
||||
return topics[0] as CentralTopic;
|
||||
}
|
||||
|
||||
/** @return {mindplot.Topic[]} selected topics */
|
||||
@ -71,9 +67,6 @@ class DesignerModel extends Events {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {mindplot.Relationship[]} selected relationships
|
||||
*/
|
||||
filterSelectedRelationships(): Relationship[] {
|
||||
const result = [];
|
||||
for (let i = 0; i < this._relationships.length; i++) {
|
||||
@ -84,50 +77,28 @@ class DesignerModel extends Events {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array.<mindplot.Relationship, mindplot.Topic>} all topics and relationships
|
||||
*/
|
||||
getEntities(): (Relationship | Topic)[] {
|
||||
let result = [].concat(this._topics);
|
||||
result = result.concat(this._relationships);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes occurrences of the given topic from the topic array
|
||||
* @param {mindplot.Topic} topic the topic to remove
|
||||
*/
|
||||
removeTopic(topic) {
|
||||
removeTopic(topic:Topic):void {
|
||||
$assert(topic, 'topic can not be null');
|
||||
this._topics = this._topics.filter((t) => t !== topic);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes occurrences of the given relationship from the relationship array
|
||||
* @param {mindplot.Relationship} rel the relationship to remove
|
||||
*/
|
||||
removeRelationship(rel) {
|
||||
removeRelationship(rel:Relationship):void {
|
||||
$assert(rel, 'rel can not be null');
|
||||
this._relationships = this._relationships.filter((r) => r !== rel);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds the given topic to the topic array
|
||||
* @param {mindplot.Topic} topic the topic to add
|
||||
* @throws will throw an error if topic is null or undefined
|
||||
* @throws will throw an error if the topic's id is not a number
|
||||
*/
|
||||
addTopic(topic: Topic): void {
|
||||
$assert(topic, 'topic can not be null');
|
||||
$assert(typeof topic.getId() === 'number', `id is not a number:${topic.getId()}`);
|
||||
this._topics.push(topic);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds the given relationship to the relationship array
|
||||
* @param {mindplot.Relationship} rel the relationship to add
|
||||
* @throws will throw an error if rel is null or undefined
|
||||
*/
|
||||
addRelationship(rel: Relationship): void {
|
||||
$assert(rel, 'rel can not be null');
|
||||
this._relationships.push(rel);
|
||||
@ -159,10 +130,6 @@ class DesignerModel extends Events {
|
||||
return (topics.length > 0) ? topics[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} id the id of the topic to be retrieved
|
||||
* @return {mindplot.Topic} the topic with the respective id
|
||||
*/
|
||||
findTopicById(id: Number): Topic {
|
||||
let result = null;
|
||||
for (let i = 0; i < this._topics.length; i++) {
|
||||
|
@ -1,8 +0,0 @@
|
||||
export type DesignerOptions = {
|
||||
locale: string,
|
||||
zoom: number,
|
||||
size: { height: number, witdh: number },
|
||||
readOnly: boolean,
|
||||
viewPort: { height: number, width: number },
|
||||
};
|
||||
|
75
packages/mindplot/src/components/DesignerOptionsBuilder.ts
Normal file
75
packages/mindplot/src/components/DesignerOptionsBuilder.ts
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 { $assert } from '@wisemapping/core-js';
|
||||
import PersistenceManager from './PersistenceManager';
|
||||
|
||||
export type DesignerOptions = {
|
||||
zoom: number,
|
||||
viewPort?: { height: number, width: number },
|
||||
size?: { height: number, width: number },
|
||||
readOnly?: boolean,
|
||||
mapId?: string,
|
||||
container: string,
|
||||
persistenceManager?: PersistenceManager,
|
||||
saveOnLoad?: boolean,
|
||||
locale?: string,
|
||||
};
|
||||
|
||||
class OptionsBuilder {
|
||||
static buildOptions(options: DesignerOptions): DesignerOptions {
|
||||
$assert(options.persistenceManager, 'persistence must be defined');
|
||||
|
||||
let containerSize = options.size;
|
||||
if (options.size == null) {
|
||||
// If it has not been defined, use browser size ...
|
||||
containerSize = {
|
||||
width: window.screen.availWidth,
|
||||
height: window.screen.availHeight,
|
||||
}
|
||||
}
|
||||
|
||||
// Is offset adjustment required
|
||||
const viewPort = {
|
||||
height: window.innerHeight,
|
||||
width: window.innerWidth,
|
||||
};
|
||||
|
||||
const defaultOptions: DesignerOptions = {
|
||||
readOnly: false,
|
||||
zoom: 0.85,
|
||||
saveOnLoad: true,
|
||||
size: containerSize,
|
||||
viewPort: viewPort,
|
||||
container: 'mindplot',
|
||||
locale: 'en',
|
||||
};
|
||||
|
||||
return { ...defaultOptions, ...options };
|
||||
}
|
||||
|
||||
static async loadOptions(jsonConf: string, options: DesignerOptions): Promise<DesignerOptions> {
|
||||
const result = await $.ajax({
|
||||
url: jsonConf,
|
||||
dataType: 'json',
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
return { ...result, ...OptionsBuilder.buildOptions(options) };
|
||||
}
|
||||
}
|
||||
export default OptionsBuilder;
|
@ -210,7 +210,7 @@ class DragTopic {
|
||||
return this.getConnectedToTopic() != null;
|
||||
}
|
||||
|
||||
isFreeLayoutOn() {
|
||||
isFreeLayoutOn(dragTopic) {
|
||||
// return this._isFreeLayoutEnabled;
|
||||
// Disable free layout ...
|
||||
return false;
|
||||
|
@ -19,44 +19,50 @@ import { $assert } from '@wisemapping/core-js';
|
||||
import { Point } from '@wisemapping/web2d';
|
||||
|
||||
class ScreenManager {
|
||||
constructor(divElement) {
|
||||
_divContainer: JQuery;
|
||||
_padding: { x: number; y: number; };
|
||||
_clickEvents: ((event: UIEvent)=>void)[];
|
||||
_scale: number;
|
||||
|
||||
constructor(divElement: JQuery) {
|
||||
$assert(divElement, 'can not be null');
|
||||
this._divContainer = divElement;
|
||||
this._padding = { x: 0, y: 0 };
|
||||
|
||||
// Ignore default click event propagation. Prevent 'click' event on drag.
|
||||
this._clickEvents = [];
|
||||
this._divContainer.bind('click', (event) => {
|
||||
this._divContainer.bind('click', (event: { stopPropagation: () => void; }) => {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
this._divContainer.bind('dblclick', (event) => {
|
||||
this._divContainer.bind('dblclick', (event: { stopPropagation: () => void; preventDefault: () => void; }) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
setScale(scale) {
|
||||
setScale(scale: number) {
|
||||
$assert(scale, 'Screen scale can not be null');
|
||||
this._scale = scale;
|
||||
}
|
||||
|
||||
addEvent(event, listener) {
|
||||
if (event === 'click') this._clickEvents.push(listener);
|
||||
else this._divContainer.bind(event, listener);
|
||||
addEvent(eventType: string, listener:any) {
|
||||
if (eventType === 'click') this._clickEvents.push(listener);
|
||||
else this._divContainer.bind(eventType, listener);
|
||||
}
|
||||
|
||||
removeEvent(event, listener) {
|
||||
removeEvent(event: string, listener: any) {
|
||||
if (event === 'click') {
|
||||
// @ts-ignore @Todo: needs review ...
|
||||
this._clickEvents.remove(listener);
|
||||
} else {
|
||||
this._divContainer.unbind(event, listener);
|
||||
}
|
||||
}
|
||||
|
||||
fireEvent(type, event) {
|
||||
fireEvent(type: string, event: UIEvent = null) {
|
||||
if (type === 'click') {
|
||||
this._clickEvents.forEach((listener) => {
|
||||
this._clickEvents.forEach((listener: (arg0: any, arg1: any) => void) => {
|
||||
listener(type, event);
|
||||
});
|
||||
} else {
|
||||
@ -64,7 +70,7 @@ class ScreenManager {
|
||||
}
|
||||
}
|
||||
|
||||
_getElementPosition(elem) {
|
||||
_getElementPosition(elem: { getPosition: () => any; }) {
|
||||
// Retrieve current element position.
|
||||
const elementPosition = elem.getPosition();
|
||||
let { x } = elementPosition;
|
||||
@ -82,7 +88,7 @@ class ScreenManager {
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
getWorkspaceIconPosition(e) {
|
||||
getWorkspaceIconPosition(e: { getImage: () => any; getSize: () => any; getGroup: () => any; }) {
|
||||
// Retrieve current icon position.
|
||||
const image = e.getImage();
|
||||
const elementPosition = image.getPosition();
|
||||
@ -117,15 +123,15 @@ class ScreenManager {
|
||||
return { x: x + topicPosition.x, y: y + topicPosition.y };
|
||||
}
|
||||
|
||||
getWorkspaceMousePosition(event) {
|
||||
getWorkspaceMousePosition(event: MouseEvent) {
|
||||
// Retrieve current mouse position.
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
|
||||
// FIXME: paulo: why? Subtract div position.
|
||||
/* var containerPosition = this.getContainer().position();
|
||||
x = x - containerPosition.x;
|
||||
y = y - containerPosition.y; */
|
||||
// Adjust the deviation of the container positioning ...
|
||||
const containerPosition = this.getContainer().position();
|
||||
x = x - containerPosition.left;
|
||||
y = y - containerPosition.top;
|
||||
|
||||
// Scale coordinate in order to be relative to the workspace. That's coordSize/size;
|
||||
x *= this._scale;
|
||||
@ -143,7 +149,7 @@ class ScreenManager {
|
||||
return this._divContainer;
|
||||
}
|
||||
|
||||
setOffset(x, y) {
|
||||
setOffset(x: number, y: number) {
|
||||
this._padding.x = x;
|
||||
this._padding.y = y;
|
||||
}
|
@ -59,7 +59,7 @@ class Workspace {
|
||||
return this._isReadOnly;
|
||||
}
|
||||
|
||||
_createWorkspace() {
|
||||
private _createWorkspace() {
|
||||
// Initialize workspace ...
|
||||
const coordOriginX = -(this._screenWidth / 2);
|
||||
const coordOriginY = -(this._screenHeight / 2);
|
||||
@ -109,10 +109,18 @@ class Workspace {
|
||||
return this._workspace.getCoordSize();
|
||||
}
|
||||
|
||||
setZoom(zoom: number, center: boolean = false) {
|
||||
setZoom(zoom: number, center: boolean = false): void {
|
||||
this._zoom = zoom;
|
||||
const workspace = this._workspace;
|
||||
|
||||
// Calculate the original boxview size ...
|
||||
let origWidth = 0;
|
||||
let origHeight = 0
|
||||
if (this._viewPort) {
|
||||
origWidth = this._viewPort.width;
|
||||
origHeight = this._viewPort.height;
|
||||
}
|
||||
|
||||
// Update coord scale...
|
||||
const coordWidth = zoom * this._screenWidth;
|
||||
const coordHeight = zoom * this._screenHeight;
|
||||
@ -125,8 +133,8 @@ class Workspace {
|
||||
}
|
||||
|
||||
// Center topic....
|
||||
let coordOriginX;
|
||||
let coordOriginY;
|
||||
let coordOriginX: number;
|
||||
let coordOriginY: number;
|
||||
|
||||
if (center) {
|
||||
if (this._viewPort) {
|
||||
@ -137,11 +145,18 @@ class Workspace {
|
||||
coordOriginY = -(coordHeight / 2);
|
||||
}
|
||||
} else {
|
||||
const coordOrigin = workspace.getCoordOrigin();
|
||||
coordOriginX = coordOrigin.x / 2;
|
||||
coordOriginY = coordOrigin.y / 2;
|
||||
}
|
||||
// Zoom keeping the center in the same place ...
|
||||
// const xPaddinng = (this._viewPort.width - origWidth) / 2;
|
||||
// const yPaddinng = (this._viewPort.height - origHeight) / 2;
|
||||
|
||||
// const coordOrigin = workspace.getCoordOrigin();
|
||||
// coordOriginX = coordOrigin.x - xPaddinng;
|
||||
// coordOriginY = coordOrigin.y - yPaddinng;
|
||||
const coordOrigin = workspace.getCoordOrigin();
|
||||
coordOriginX = coordOrigin.x;
|
||||
coordOriginY = coordOrigin.y;
|
||||
|
||||
}
|
||||
workspace.setCoordOrigin(coordOriginX, coordOriginY);
|
||||
|
||||
// Update screen.
|
||||
@ -228,7 +243,7 @@ class Workspace {
|
||||
screenManager.addEvent('mousedown', mouseDownListener);
|
||||
}
|
||||
|
||||
setViewPort(size:{ height: number, width: number }) {
|
||||
setViewPort(size: { height: number, width: number }) {
|
||||
this._viewPort = size;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
try {
|
||||
$(document).trigger('loadcomplete', 'mind');
|
||||
} catch (e) {
|
||||
console.error(e.stack);
|
||||
}
|
@ -31,7 +31,7 @@ import AccountSettingsPanel from './AccountSettingsPanel';
|
||||
import Designer from '../Designer';
|
||||
|
||||
class Menu extends IMenu {
|
||||
constructor(designer: Designer, containerId: string, mapId: string, readOnly: boolean = false, baseUrl = '') {
|
||||
constructor(designer: Designer, containerId: string, mapId: string, readOnly: boolean = false, baseUrl:string = '') {
|
||||
super(designer, containerId, mapId);
|
||||
const saveElem = $('#save');
|
||||
|
||||
@ -259,6 +259,12 @@ class Menu extends IMenu {
|
||||
});
|
||||
Menu._registerTooltip('zoom-minus', $msg('ZOOM_OUT'));
|
||||
|
||||
this._addButton('position', false, false, () => {
|
||||
designer.setZoomToFit();
|
||||
});
|
||||
Menu._registerTooltip('position', $msg('CENTER_POSITION'));
|
||||
|
||||
|
||||
const undoButton = this._addButton('undoEdition', false, false, () => {
|
||||
designer.undo();
|
||||
});
|
||||
|
@ -25,13 +25,15 @@ import {
|
||||
import LoadingModal from './components/widget/LoadingModal';
|
||||
import {
|
||||
buildDesigner,
|
||||
buildOptions,
|
||||
} from './components/DesignerBuilder';
|
||||
import RESTPersistenceManager from './components/RestPersistenceManager';
|
||||
import PersistenceManager from './components/PersistenceManager';
|
||||
import LocalStorageManager from './components/LocalStorageManager';
|
||||
import DesignerOptionsBuilder from './components/DesignerOptionsBuilder';
|
||||
|
||||
|
||||
// This hack is required to initialize Bootstrap. In future, this should be removed.
|
||||
//@ts-ignore
|
||||
global.jQuery = jquery;
|
||||
require('@libraries/bootstrap/js/bootstrap');
|
||||
|
||||
@ -39,7 +41,7 @@ const loadingModal = new LoadingModal();
|
||||
loadingModal.show();
|
||||
|
||||
// Configure designer options ...
|
||||
let persistence;
|
||||
let persistence:PersistenceManager;
|
||||
if (!global.memoryPersistence && !global.readOnly) {
|
||||
persistence = new RESTPersistenceManager({
|
||||
documentUrl: '/c/restful/maps/{id}/document',
|
||||
@ -55,13 +57,15 @@ if (!global.memoryPersistence && !global.readOnly) {
|
||||
// Obtain map zoom from query param if it was specified...
|
||||
const params = new URLSearchParams(window.location.search.substring(1));
|
||||
|
||||
const zoomParam = Number.parseFloat(params.get('zoom'), 10);
|
||||
const options = buildOptions({
|
||||
persistenceManager: persistence,
|
||||
readOnly: global.readOnly || false,
|
||||
mapId: global.mapId,
|
||||
zoom: zoomParam || global.userOptions.zoom,
|
||||
});
|
||||
const zoomParam = Number.parseFloat(params.get('zoom'));
|
||||
const options = DesignerOptionsBuilder.buildOptions(
|
||||
{
|
||||
persistenceManager: persistence,
|
||||
readOnly: Boolean(global.readOnly || false),
|
||||
mapId: global.mapId,
|
||||
container: 'mindplot',
|
||||
zoom: zoomParam || global.userOptions.zoom,
|
||||
});
|
||||
|
||||
// Build designer ...
|
||||
const designer = buildDesigner(options);
|
||||
@ -76,5 +80,5 @@ const mindmap = instance.load(global.mapId);
|
||||
designer.loadMap(mindmap);
|
||||
|
||||
if (global.mindmapLocked) {
|
||||
$notify(global.mindmapLockedMsg, false);
|
||||
$notify(global.mindmapLockedMsg);
|
||||
}
|
@ -19,7 +19,6 @@ body {
|
||||
div#mindplot {
|
||||
position: relative;
|
||||
top: @header-toolbar-height;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@ -154,6 +153,22 @@ div#bottom-logo {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
div#position {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#position-button {
|
||||
cursor: pointer;
|
||||
border: solid black 1px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 40px 40px;
|
||||
background-color: #FFF;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#zoom-button {
|
||||
width: 40px;
|
||||
border: 0;
|
||||
@ -161,6 +176,7 @@ div#bottom-logo {
|
||||
|
||||
#zoom-plus,
|
||||
#zoom-minus {
|
||||
border: solid black 1px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -1,10 +1,8 @@
|
||||
@header-height : 0px;
|
||||
@header-toolbar-height : 50px;
|
||||
@header-info-height : @header-height - @header-toolbar-height;
|
||||
|
||||
div#header {
|
||||
width: 100%;
|
||||
height: @header-height;
|
||||
height: 0px;
|
||||
background: #202020;
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
|
@ -115,6 +115,11 @@
|
||||
<img src="images/minus.svg" />
|
||||
</button>
|
||||
</div>
|
||||
<div id="position">
|
||||
<button id="position-button">
|
||||
<img src="images/center_focus.svg" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bottom-logo"></div>
|
||||
<div id="headerNotifier"></div>
|
||||
|
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></svg>
|
After Width: | Height: | Size: 440 B |
@ -1,7 +1,8 @@
|
||||
import '../css/editor.less';
|
||||
import { buildDesigner, buildOptions } from '../../../../src/components/DesignerBuilder';
|
||||
import { buildDesigner } from '../../../../src/components/DesignerBuilder';
|
||||
import { PersistenceManager, LocalStorageManager } from '../../../../src';
|
||||
import LoadingModal from '../../../../src/components/widget/LoadingModal';
|
||||
import DesignerOptionsBuilder from '../../../../src/components/DesignerOptionsBuilder';
|
||||
|
||||
// Account details ...
|
||||
global.accountName = 'Test User';
|
||||
@ -11,11 +12,14 @@ const loadingModal = new LoadingModal();
|
||||
loadingModal.show();
|
||||
|
||||
const p = new LocalStorageManager('samples/{id}.wxml');
|
||||
const options = buildOptions({ persistenceManager: p });
|
||||
const options = DesignerOptionsBuilder.buildOptions({
|
||||
persistenceManager: p
|
||||
});
|
||||
const designer = buildDesigner(options);
|
||||
|
||||
designer.addEvent('loadSuccess', () => {
|
||||
loadingModal.hide();
|
||||
// Hack for automation testing ...
|
||||
document.getElementById('mindplot').classList.add('ready');
|
||||
});
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
import '../css/embedded.less';
|
||||
import { buildDesigner, buildOptions } from '../../../../src/components/DesignerBuilder';
|
||||
import { buildDesigner } from '../../../../src/components/DesignerBuilder';
|
||||
import { PersistenceManager, LocalStorageManager } from '../../../../src';
|
||||
import DesignerOptionsBuilder from '../../../../src/components/DesignerOptionsBuilder';
|
||||
|
||||
// Options has been defined in by a external ile ?
|
||||
const p = new LocalStorageManager('samples/{id}.wxml');
|
||||
const options = buildOptions({ persistenceManager: p });
|
||||
const options = DesignerOptionsBuilder.buildOptions({ persistenceManager: p });
|
||||
const designer = buildDesigner(options);
|
||||
|
||||
designer.addEvent('loadSuccess', () => {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import '../css/viewmode.less';
|
||||
import { buildDesigner, buildOptions } from '../../../../src/components/DesignerBuilder';
|
||||
import { buildDesigner } from '../../../../src/components/DesignerBuilder';
|
||||
import { PersistenceManager, LocalStorageManager } from '../../../../src';
|
||||
import DesignerOptionsBuilder from '../../../../src/components/DesignerOptionsBuilder';
|
||||
|
||||
|
||||
const p = new LocalStorageManager('samples/{id}.wxml');
|
||||
const options = buildOptions({ persistenceManager: p, readOnly: true, saveOnLoad: false });
|
||||
const options = DesignerOptionsBuilder.buildOptions({ persistenceManager: p, readOnly: true, saveOnLoad: false });
|
||||
|
||||
// Obtain map id from query param
|
||||
const params = new URLSearchParams(window.location.search.substring(1));
|
||||
|
@ -11,7 +11,7 @@ module.exports = {
|
||||
},
|
||||
entry: {
|
||||
mindplot: './src/index.js',
|
||||
loader: './src/indexLoader.js',
|
||||
loader: './src/indexLoader.ts',
|
||||
},
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
|
@ -78,8 +78,6 @@ class Workspace extends ElementClass {
|
||||
*/
|
||||
static _createDivContainer() {
|
||||
const container = window.document.createElement('div');
|
||||
// container.id = 'workspaceContainer';
|
||||
// container.style.overflow = 'hidden';
|
||||
container.style.position = 'relative';
|
||||
container.style.top = '0px';
|
||||
container.style.left = '0px';
|
||||
|
@ -2561,6 +2561,13 @@
|
||||
jest-diff "^27.0.0"
|
||||
pretty-format "^27.0.0"
|
||||
|
||||
"@types/jquery@^3.5.11":
|
||||
version "3.5.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.5.11.tgz#fb2a255e8376779e89a10ddd04bfc1a93398f861"
|
||||
integrity sha512-lYZGdfOtUa0XFjIATQgiogqeTY5PNNMOmp3Jq48ghmJALL8t/IqABRqlEwdHfuUdA8iIE1uGD1HoI4a7Tiy6OA==
|
||||
dependencies:
|
||||
"@types/sizzle" "*"
|
||||
|
||||
"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
|
||||
version "7.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
|
||||
@ -2671,7 +2678,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.4.tgz#0ecc1b9259b76598ef01942f547904ce61a6a77d"
|
||||
integrity sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A==
|
||||
|
||||
"@types/sizzle@^2.3.2":
|
||||
"@types/sizzle@*", "@types/sizzle@^2.3.2":
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef"
|
||||
integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==
|
||||
|
Loading…
Reference in New Issue
Block a user