Add delay render support.

This commit is contained in:
Paulo Gustavo Veiga 2022-11-16 21:12:33 -08:00
parent a1f0fa6281
commit 046215898e
10 changed files with 110 additions and 39 deletions

View File

@ -11,10 +11,16 @@ context('Relationship Topics', () => {
cy.contains('Try it Now!').first().click();
cy.get('[test-id="11-15-relationship"]').first().click({ force: true });
cy.get('[test-id="11-15-relationship"]').should('exist');
cy.matchImageSnapshot('addRelationship');
});
it('Delete Relationship', () => {
cy.contains('Features').first().click();
cy.get(`[aria-label="Add Relationship"]`).first().click();
cy.contains('Try it Now!').first().click();
cy.get('[test-id="11-15-relationship"]').click({ force: true });
cy.get('body').type('{backspace}');

View File

@ -32,7 +32,7 @@ class Editor {
}
isMapLoadded(): boolean {
return this.component?.getDesigner()?.getMindmap() != null;
return this.component.isLoaded();
}
save(minor: boolean): void {
@ -57,9 +57,9 @@ class Editor {
mapId: string,
persistenceManager: PersistenceManager,
widgetManager: WidgetManager,
): void {
): Promise<void> {
this.component.buildDesigner(persistenceManager, widgetManager);
this.component.loadMap(mapId);
return this.component.loadMap(mapId);
}
registerEvents(canvasUpdate: (timestamp: number) => void, capability: Capability): void {

View File

@ -79,10 +79,12 @@ const Editor = ({
const capability = new Capability(options.mode, mapInfo.isLocked());
const mindplotRef = useCallback((component: MindplotWebComponent) => {
// Initialized model ...
const model = new Model(component);
model.loadMindmap(mapInfo.getId(), persistenceManager, widgetManager);
model.registerEvents(setCanvasUpdate, capability);
// Force refresh after map load ...
model.loadMindmap(mapInfo.getId(), persistenceManager, widgetManager).then(() => {
setCanvasUpdate(Date.now());
});
setModel(model);
}, []);
@ -137,7 +139,7 @@ const Editor = ({
message={mapInfo.isLocked() ? mapInfo.getLockedMessage() : ''}
/>
{!model && (
{!model?.isMapLoadded() && (
<SpinnerCentered>
<Vortex
visible={true}

View File

@ -42,9 +42,10 @@ const container = document.getElementById('root');
const root = createRoot(container!);
root.render(
<Editor
mapInfo={new MapInfoImpl('welcome', 'Develop Map Title', false)}
mapInfo={new MapInfoImpl(mapId, 'Develop Map Title', false)}
options={options}
persistenceManager={persistence}
onAction={(action) => console.log('action called:', action)}
onLoad={initialization}
/>);
/>,
);

File diff suppressed because one or more lines are too long

View File

@ -577,14 +577,12 @@ class Designer extends Events {
return { zoom: model.getZoom() };
}
/**
* @param {mindplot.Mindmap} mindmap
* @throws will throw an error if mindmapModel is null or undefined
*/
loadMap(mindmap: Mindmap): void {
loadMap(mindmap: Mindmap): Promise<void> {
$assert(mindmap, 'mindmapModel can not be null');
this._mindmap = mindmap;
this._workspace.enableQueueRender(true);
// Init layout manager ...
const size = { width: 25, height: 25 };
const layoutManager = new LayoutManager(mindmap.getCentralTopic().getId(), size);
@ -601,23 +599,29 @@ class Designer extends Events {
// Building node graph ...
const branches = mindmap.getBranches();
const nodesGraph: Topic[] = [];
branches.forEach((branch) => {
const nodeGraph = this.nodeModelToTopic(branch);
nodeGraph.setBranchVisibility(true);
nodesGraph.push(nodeGraph);
});
// Connect relationships ...
const relationships = mindmap.getRelationships();
relationships.forEach((relationship) => this._relationshipModelToRelationship(relationship));
// Place the focus on the Central Topic
const centralTopic = this.getModel().getCentralTopic();
this.goToNode(centralTopic);
// Finally, sort the map ...
EventBus.instance.fireEvent('forceLayout');
return this._workspace.enableQueueRender(false).then(() => {
// Connect relationships ...
const relationships = mindmap.getRelationships();
relationships.forEach((relationship) => this._relationshipModelToRelationship(relationship));
this.fireEvent('loadSuccess');
// Render nodes ...
nodesGraph.forEach((topic) => topic.setVisibility(true));
// Finally, sort the map ...
EventBus.instance.fireEvent('forceLayout');
this.fireEvent('loadSuccess');
});
}
getMindmap(): Mindmap {

View File

@ -3,7 +3,6 @@ import buildDesigner from './DesignerBuilder';
import DesignerOptionsBuilder from './DesignerOptionsBuilder';
import EditorRenderMode from './EditorRenderMode';
import LocalStorageManager from './LocalStorageManager';
import Mindmap from './model/Mindmap';
import PersistenceManager from './PersistenceManager';
import WidgetManager from './WidgetManager';
import mindplotStyles from './styles/mindplot-styles';
@ -27,12 +26,12 @@ export type MindplotWebComponentInterface = {
class MindplotWebComponent extends HTMLElement {
private _shadowRoot: ShadowRoot;
private _mindmap: Mindmap;
private _designer: Designer;
private saveRequired: boolean;
private _isLoaded: boolean;
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: 'open' });
@ -77,6 +76,16 @@ class MindplotWebComponent extends HTMLElement {
});
this.registerShortcuts();
this._designer.addEvent('loadSuccess', (): void => {
this._isLoaded = true;
});
return this._designer;
}
isLoaded(): boolean {
return this._isLoaded;
}
private registerShortcuts() {
@ -100,10 +109,9 @@ class MindplotWebComponent extends HTMLElement {
* Load map in designer throught persistence manager instance
* @param id the map id to be loaded.
*/
async loadMap(id: string): Promise<void> {
loadMap(id: string): Promise<void> {
const instance = PersistenceManager.getInstance();
this._mindmap = await instance.load(id);
this._designer.loadMap(this._mindmap);
return instance.load(id).then((mindmap) => this._designer.loadMap(mindmap));
}
/**

View File

@ -61,12 +61,11 @@ abstract class PersistenceManager {
return result;
}
load(mapId: string): Promise<Mindmap> {
async load(mapId: string): Promise<Mindmap> {
$assert(mapId, 'mapId can not be null');
return this.loadMapDom(mapId).then((document) => {
console.log(`Loading map with is ${mapId}}`);
return PersistenceManager.loadFromDom(mapId, document);
});
// eslint-disable-next-line arrow-body-style
const document = await this.loadMapDom(mapId);
return PersistenceManager.loadFromDom(mapId, document);
}
triggerError(error: PersistenceError) {

View File

@ -35,6 +35,10 @@ class Workspace {
private _visibleAreaSize: SizeType;
private _renderQueue: Element2D[];
private queueRenderEnabled: boolean;
constructor(screenManager: ScreenManager, zoom: number, isReadOnly: boolean) {
// Create a suitable container ...
$assert(screenManager, 'Div container can not be null');
@ -66,6 +70,8 @@ class Workspace {
});
this.setZoom(zoom, true);
this._renderQueue = [];
}
private _adjustWorkspace(): void {
@ -97,6 +103,14 @@ class Workspace {
}
append(shape: Element2D): void {
if (this.queueRenderEnabled) {
this._renderQueue.push(shape);
} else {
this.appendInternal(shape);
}
}
private appendInternal(shape: Element2D): void {
if ($defined(shape.addToWorkspace)) {
shape.addToWorkspace(this);
} else {
@ -104,6 +118,37 @@ class Workspace {
}
}
enableQueueRender(value: boolean): Promise<void> {
this.queueRenderEnabled = value;
let result = Promise.resolve();
if (!value) {
result = this.processRenderQueue(this._renderQueue.reverse(), 300);
}
return result;
}
private processRenderQueue(renderQueue: Element2D[], batch: number): Promise<void> {
function delay(t: number) {
return new Promise((resolve) => setTimeout(resolve, t));
}
let result: Promise<void>;
if (renderQueue.length > 0) {
result = new Promise((resolve: (queue: Element2D[]) => void) => {
for (let i = 0; i < batch && renderQueue.length > 0; i++) {
const elem = renderQueue.pop();
this.appendInternal(elem);
}
resolve(renderQueue);
}).then((queue) => delay(30).then(() => this.processRenderQueue(queue, batch)));
} else {
result = Promise.resolve();
}
return result;
}
removeChild(shape: Element2D): void {
// Element is a node, not a web2d element?
if ($defined(shape.removeFromWorkspace)) {

View File

@ -159,12 +159,7 @@ class TextPeer extends ElementPeer {
}
getWidth() {
let computedWidth = this._native.getBBox().width;
if (computedWidth === 0) {
const bbox = this._native.getBBox();
computedWidth = bbox.width;
}
const computedWidth = this._native.getBBox().width;
let width = parseInt(computedWidth, 10);
width += this._font.getWidthMargin();
return width;