From cdd044c41d79988193eaecb44e530c02ffd5e558 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Sun, 9 Jan 2022 10:43:04 -0800 Subject: [PATCH] Add center position action. Improve screenmanager positioning Change several clasess to typescript --- packages/mindplot/package.json | 1 + packages/mindplot/src/components/.gitignore | 1 - packages/mindplot/src/components/Designer.ts | 82 ++++++------------- ...{DesignerBuilder.js => DesignerBuilder.ts} | 50 +++-------- .../mindplot/src/components/DesignerModel.ts | 49 ++--------- .../src/components/DesignerOptions.ts | 8 -- .../src/components/DesignerOptionsBuilder.ts | 75 +++++++++++++++++ packages/mindplot/src/components/DragTopic.js | 2 +- .../{ScreenManager.js => ScreenManager.ts} | 42 ++++++---- packages/mindplot/src/components/Workspace.ts | 33 ++++++-- packages/mindplot/src/components/footer.js | 7 -- .../mindplot/src/components/widget/Menu.ts | 8 +- .../src/{indexLoader.js => indexLoader.ts} | 24 +++--- .../playground/map-render/css/editor.less | 18 +++- .../playground/map-render/css/header.less | 4 +- .../playground/map-render/html/editor.html | 5 ++ .../map-render/images/center_focus.svg | 1 + .../test/playground/map-render/js/editor.js | 8 +- .../test/playground/map-render/js/embedded.js | 5 +- .../test/playground/map-render/js/viewmode.js | 6 +- packages/mindplot/webpack.common.js | 2 +- packages/web2d/src/components/Workspace.js | 2 - yarn.lock | 9 +- 23 files changed, 233 insertions(+), 209 deletions(-) delete mode 100644 packages/mindplot/src/components/.gitignore rename packages/mindplot/src/components/{DesignerBuilder.js => DesignerBuilder.ts} (67%) delete mode 100644 packages/mindplot/src/components/DesignerOptions.ts create mode 100644 packages/mindplot/src/components/DesignerOptionsBuilder.ts rename packages/mindplot/src/components/{ScreenManager.js => ScreenManager.ts} (75%) delete mode 100644 packages/mindplot/src/components/footer.js rename packages/mindplot/src/{indexLoader.js => indexLoader.ts} (84%) create mode 100644 packages/mindplot/test/playground/map-render/images/center_focus.svg diff --git a/packages/mindplot/package.json b/packages/mindplot/package.json index cf38ceb7..b12fb861 100644 --- a/packages/mindplot/package.json +++ b/packages/mindplot/package.json @@ -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", diff --git a/packages/mindplot/src/components/.gitignore b/packages/mindplot/src/components/.gitignore deleted file mode 100644 index cc4e9f6e..00000000 --- a/packages/mindplot/src/components/.gitignore +++ /dev/null @@ -1 +0,0 @@ -MessageBundle_* \ No newline at end of file diff --git a/packages/mindplot/src/components/Designer.ts b/packages/mindplot/src/components/Designer.ts index 8193428e..58d880e2 100644 --- a/packages/mindplot/src/components/Designer.ts +++ b/packages/mindplot/src/components/Designer.ts @@ -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); diff --git a/packages/mindplot/src/components/DesignerBuilder.js b/packages/mindplot/src/components/DesignerBuilder.ts similarity index 67% rename from packages/mindplot/src/components/DesignerBuilder.js rename to packages/mindplot/src/components/DesignerBuilder.ts index d9527f63..8fea2c21 100644 --- a/packages/mindplot/src/components/DesignerBuilder.js +++ b/packages/mindplot/src/components/DesignerBuilder.ts @@ -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) { - window.waitDialog.close(); + // @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) }; -} diff --git a/packages/mindplot/src/components/DesignerModel.ts b/packages/mindplot/src/components/DesignerModel.ts index e965c714..14f54595 100644 --- a/packages/mindplot/src/components/DesignerModel.ts +++ b/packages/mindplot/src/components/DesignerModel.ts @@ -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.} 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++) { diff --git a/packages/mindplot/src/components/DesignerOptions.ts b/packages/mindplot/src/components/DesignerOptions.ts deleted file mode 100644 index 588e3bcc..00000000 --- a/packages/mindplot/src/components/DesignerOptions.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type DesignerOptions = { - locale: string, - zoom: number, - size: { height: number, witdh: number }, - readOnly: boolean, - viewPort: { height: number, width: number }, - }; - \ No newline at end of file diff --git a/packages/mindplot/src/components/DesignerOptionsBuilder.ts b/packages/mindplot/src/components/DesignerOptionsBuilder.ts new file mode 100644 index 00000000..3ce38bad --- /dev/null +++ b/packages/mindplot/src/components/DesignerOptionsBuilder.ts @@ -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 { + const result = await $.ajax({ + url: jsonConf, + dataType: 'json', + method: 'get', + }); + + return { ...result, ...OptionsBuilder.buildOptions(options) }; + } +} +export default OptionsBuilder; \ No newline at end of file diff --git a/packages/mindplot/src/components/DragTopic.js b/packages/mindplot/src/components/DragTopic.js index f5c21d58..f14c6df0 100644 --- a/packages/mindplot/src/components/DragTopic.js +++ b/packages/mindplot/src/components/DragTopic.js @@ -210,7 +210,7 @@ class DragTopic { return this.getConnectedToTopic() != null; } - isFreeLayoutOn() { + isFreeLayoutOn(dragTopic) { // return this._isFreeLayoutEnabled; // Disable free layout ... return false; diff --git a/packages/mindplot/src/components/ScreenManager.js b/packages/mindplot/src/components/ScreenManager.ts similarity index 75% rename from packages/mindplot/src/components/ScreenManager.js rename to packages/mindplot/src/components/ScreenManager.ts index 9996cd9b..1f9c4fee 100644 --- a/packages/mindplot/src/components/ScreenManager.js +++ b/packages/mindplot/src/components/ScreenManager.ts @@ -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; } diff --git a/packages/mindplot/src/components/Workspace.ts b/packages/mindplot/src/components/Workspace.ts index 24098cdb..2cb7a43a 100644 --- a/packages/mindplot/src/components/Workspace.ts +++ b/packages/mindplot/src/components/Workspace.ts @@ -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; } } diff --git a/packages/mindplot/src/components/footer.js b/packages/mindplot/src/components/footer.js deleted file mode 100644 index 0d30003a..00000000 --- a/packages/mindplot/src/components/footer.js +++ /dev/null @@ -1,7 +0,0 @@ -import $ from 'jquery'; - -try { - $(document).trigger('loadcomplete', 'mind'); -} catch (e) { - console.error(e.stack); -} diff --git a/packages/mindplot/src/components/widget/Menu.ts b/packages/mindplot/src/components/widget/Menu.ts index b530a6d5..63c88fe5 100644 --- a/packages/mindplot/src/components/widget/Menu.ts +++ b/packages/mindplot/src/components/widget/Menu.ts @@ -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(); }); diff --git a/packages/mindplot/src/indexLoader.js b/packages/mindplot/src/indexLoader.ts similarity index 84% rename from packages/mindplot/src/indexLoader.js rename to packages/mindplot/src/indexLoader.ts index 13549a8f..27f94fa4 100644 --- a/packages/mindplot/src/indexLoader.js +++ b/packages/mindplot/src/indexLoader.ts @@ -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); } diff --git a/packages/mindplot/test/playground/map-render/css/editor.less b/packages/mindplot/test/playground/map-render/css/editor.less index f4fc191d..211ea210 100644 --- a/packages/mindplot/test/playground/map-render/css/editor.less +++ b/packages/mindplot/test/playground/map-render/css/editor.less @@ -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; diff --git a/packages/mindplot/test/playground/map-render/css/header.less b/packages/mindplot/test/playground/map-render/css/header.less index 1913a745..53188968 100644 --- a/packages/mindplot/test/playground/map-render/css/header.less +++ b/packages/mindplot/test/playground/map-render/css/header.less @@ -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; diff --git a/packages/mindplot/test/playground/map-render/html/editor.html b/packages/mindplot/test/playground/map-render/html/editor.html index a36a5093..65cbcfcd 100644 --- a/packages/mindplot/test/playground/map-render/html/editor.html +++ b/packages/mindplot/test/playground/map-render/html/editor.html @@ -115,6 +115,11 @@ +
+ +
diff --git a/packages/mindplot/test/playground/map-render/images/center_focus.svg b/packages/mindplot/test/playground/map-render/images/center_focus.svg new file mode 100644 index 00000000..e8017c36 --- /dev/null +++ b/packages/mindplot/test/playground/map-render/images/center_focus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/mindplot/test/playground/map-render/js/editor.js b/packages/mindplot/test/playground/map-render/js/editor.js index 132e9a23..93a38615 100644 --- a/packages/mindplot/test/playground/map-render/js/editor.js +++ b/packages/mindplot/test/playground/map-render/js/editor.js @@ -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'); }); diff --git a/packages/mindplot/test/playground/map-render/js/embedded.js b/packages/mindplot/test/playground/map-render/js/embedded.js index 516e9fdd..8d32e68c 100644 --- a/packages/mindplot/test/playground/map-render/js/embedded.js +++ b/packages/mindplot/test/playground/map-render/js/embedded.js @@ -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', () => { diff --git a/packages/mindplot/test/playground/map-render/js/viewmode.js b/packages/mindplot/test/playground/map-render/js/viewmode.js index 49afd168..57bdea35 100644 --- a/packages/mindplot/test/playground/map-render/js/viewmode.js +++ b/packages/mindplot/test/playground/map-render/js/viewmode.js @@ -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)); diff --git a/packages/mindplot/webpack.common.js b/packages/mindplot/webpack.common.js index 06dcef85..da5cb401 100644 --- a/packages/mindplot/webpack.common.js +++ b/packages/mindplot/webpack.common.js @@ -11,7 +11,7 @@ module.exports = { }, entry: { mindplot: './src/index.js', - loader: './src/indexLoader.js', + loader: './src/indexLoader.ts', }, mode: 'production', devtool: 'source-map', diff --git a/packages/web2d/src/components/Workspace.js b/packages/web2d/src/components/Workspace.js index 821f5147..c0dae9a1 100644 --- a/packages/web2d/src/components/Workspace.js +++ b/packages/web2d/src/components/Workspace.js @@ -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'; diff --git a/yarn.lock b/yarn.lock index eea3ab34..8397e00c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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==