mirror of
https://github.com/projectstorm/react-diagrams.git
synced 2026-03-13 09:50:09 +08:00
massive performance wins
This commit is contained in:
@@ -36,8 +36,6 @@ export class DiagramEngine extends BaseObserver<DiagramEngineListener> {
|
||||
|
||||
diagramModel: DiagramModel;
|
||||
canvas: HTMLDivElement;
|
||||
paintableWidgets: {};
|
||||
linksThatHaveInitiallyRendered: {};
|
||||
maxNumberPointsPerLink: number;
|
||||
|
||||
constructor() {
|
||||
@@ -70,7 +68,6 @@ export class DiagramEngine extends BaseObserver<DiagramEngineListener> {
|
||||
setup(this.actionFactories);
|
||||
|
||||
this.canvas = null;
|
||||
this.paintableWidgets = null;
|
||||
// this.linksThatHaveInitiallyRendered = {};
|
||||
}
|
||||
|
||||
@@ -82,10 +79,6 @@ export class DiagramEngine extends BaseObserver<DiagramEngineListener> {
|
||||
});
|
||||
}
|
||||
|
||||
clearRepaintEntities() {
|
||||
this.paintableWidgets = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a model and element under the mouse cursor
|
||||
*/
|
||||
@@ -133,26 +126,6 @@ export class DiagramEngine extends BaseObserver<DiagramEngineListener> {
|
||||
return null;
|
||||
}
|
||||
|
||||
enableRepaintEntities(entities: BaseModel[]) {
|
||||
this.paintableWidgets = {};
|
||||
entities.forEach(entity => {
|
||||
//if a node is requested to repaint, add all of its links
|
||||
if (entity instanceof NodeModel) {
|
||||
_.forEach(entity.getPorts(), port => {
|
||||
_.forEach(port.getLinks(), link => {
|
||||
this.paintableWidgets[link.getID()] = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (entity instanceof PointModel) {
|
||||
this.paintableWidgets[entity.getLink().getID()] = true;
|
||||
}
|
||||
|
||||
this.paintableWidgets[entity.getID()] = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a model is locked by running through
|
||||
* its parents to see if they are locked first
|
||||
@@ -166,19 +139,6 @@ export class DiagramEngine extends BaseObserver<DiagramEngineListener> {
|
||||
return model.isLocked();
|
||||
}
|
||||
|
||||
recalculatePortsVisually() {
|
||||
this.linksThatHaveInitiallyRendered = {};
|
||||
}
|
||||
|
||||
canEntityRepaint(baseModel: BaseModel) {
|
||||
//no rules applied, allow repaint
|
||||
if (this.paintableWidgets === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.paintableWidgets[baseModel.getID()] !== undefined;
|
||||
}
|
||||
|
||||
setCanvas(canvas?: HTMLDivElement) {
|
||||
if (this.canvas !== canvas) {
|
||||
this.canvas = canvas;
|
||||
@@ -190,7 +150,6 @@ export class DiagramEngine extends BaseObserver<DiagramEngineListener> {
|
||||
|
||||
setDiagramModel(model: DiagramModel) {
|
||||
this.diagramModel = model;
|
||||
this.recalculatePortsVisually();
|
||||
}
|
||||
|
||||
getDiagramModel(): DiagramModel {
|
||||
|
||||
@@ -33,14 +33,6 @@ export class MoveItemsAction extends AbstractMouseAction {
|
||||
this.model.getGridPosition(model.initialX + amountX / amountZoom),
|
||||
this.model.getGridPosition(model.initialY + amountY / amountZoom)
|
||||
);
|
||||
|
||||
if (model.model instanceof NodeModel) {
|
||||
// update port coordinates as well
|
||||
_.forEach(model.model.getPorts(), port => {
|
||||
const portCoords = this.engine.getPortCoords(port);
|
||||
port.updateCoords(portCoords);
|
||||
});
|
||||
}
|
||||
} else if (model.model instanceof PointModel) {
|
||||
// we want points that are connected to ports, to not necessarily snap to grid
|
||||
// this stuff needs to be pixel perfect, dont touch it
|
||||
@@ -89,7 +81,6 @@ export class MoveItemsAction extends AbstractMouseAction {
|
||||
link.setTargetPort(element.model);
|
||||
link.getLastPoint().setPosition(this.engine.getPortCenter(element.model));
|
||||
}
|
||||
delete this.engine.linksThatHaveInitiallyRendered[link.getID()];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -134,8 +125,6 @@ export class MoveItemsAction extends AbstractMouseAction {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.engine.clearRepaintEntities();
|
||||
}
|
||||
|
||||
fireMouseDown(event: ActionFactoryActivationEvent) {
|
||||
@@ -184,6 +173,5 @@ export class MoveItemsAction extends AbstractMouseAction {
|
||||
initialY: item.getY()
|
||||
};
|
||||
});
|
||||
this.engine.enableRepaintEntities(this.model.getSelectedItems());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,6 @@ export class DiagramWidget extends BaseWidget<DiagramProps, DiagramState> {
|
||||
if (this.state.action && this.state.action instanceof AbstractMouseAction) {
|
||||
this.state.action.fireMouseUp(event);
|
||||
}
|
||||
this.props.diagramEngine.clearRepaintEntities();
|
||||
this.stopFiringAction();
|
||||
document.removeEventListener('mousemove', this.onMouseMove);
|
||||
document.removeEventListener('mouseup', this.onMouseUp);
|
||||
@@ -171,7 +170,6 @@ export class DiagramWidget extends BaseWidget<DiagramProps, DiagramState> {
|
||||
|
||||
getActionForEvent(event: MouseEvent): AbstractAction {
|
||||
event.persist();
|
||||
this.props.diagramEngine.clearRepaintEntities();
|
||||
const { diagramEngine } = this.props;
|
||||
const model = diagramEngine.getMouseElement(event);
|
||||
|
||||
@@ -238,14 +236,10 @@ export class DiagramWidget extends BaseWidget<DiagramProps, DiagramState> {
|
||||
diagramModel.getOffsetY() - heightDiff * yFactor
|
||||
);
|
||||
|
||||
diagramEngine.enableRepaintEntities([]);
|
||||
this.forceUpdate(() => {
|
||||
this.props.diagramEngine.clearRepaintEntities();
|
||||
});
|
||||
this.forceUpdate();
|
||||
}
|
||||
}}
|
||||
onMouseDown={event => {
|
||||
diagramEngine.clearRepaintEntities();
|
||||
// try and get an action for this event
|
||||
const action = this.getActionForEvent(event);
|
||||
if (action) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { PortModel } from '../models/PortModel';
|
||||
import { MouseEvent } from 'react';
|
||||
import * as _ from 'lodash';
|
||||
import { LabelWidget } from './LabelWidget';
|
||||
import { PeformanceWidget } from './PeformanceWidget';
|
||||
|
||||
export interface LinkProps {
|
||||
link: LinkModel;
|
||||
@@ -98,14 +99,20 @@ export class LinkWidget extends React.Component<LinkProps, LinkState> {
|
||||
|
||||
//generate links
|
||||
return (
|
||||
<g>
|
||||
{React.cloneElement(this.props.diagramEngine.generateWidgetForLink(link), {
|
||||
pointAdded: this.props.pointAdded
|
||||
})}
|
||||
{_.map(this.props.link.getLabels(), (labelModel, index) => {
|
||||
return <LabelWidget engine={this.props.diagramEngine} label={labelModel} index={index} />;
|
||||
})}
|
||||
</g>
|
||||
<PeformanceWidget serialized={this.props.link.serialize()}>
|
||||
{() => {
|
||||
return (
|
||||
<g>
|
||||
{React.cloneElement(this.props.diagramEngine.generateWidgetForLink(link), {
|
||||
pointAdded: this.props.pointAdded
|
||||
})}
|
||||
{_.map(this.props.link.getLabels(), (labelModel, index) => {
|
||||
return <LabelWidget engine={this.props.diagramEngine} label={labelModel} index={index} />;
|
||||
})}
|
||||
</g>
|
||||
);
|
||||
}}
|
||||
</PeformanceWidget>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { BaseWidget, BaseWidgetProps } from './BaseWidget';
|
||||
import { BaseEntityEvent } from '../core-models/BaseEntity';
|
||||
import { BaseModel } from '../core-models/BaseModel';
|
||||
import { ListenerHandle } from '../core/BaseObserver';
|
||||
import { PeformanceWidget } from './PeformanceWidget';
|
||||
|
||||
export interface NodeProps extends BaseWidgetProps {
|
||||
node: NodeModel;
|
||||
@@ -23,10 +24,6 @@ export class NodeWidget extends BaseWidget<NodeProps> {
|
||||
this.ref = React.createRef();
|
||||
}
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return this.props.diagramEngine.canEntityRepaint(this.props.node);
|
||||
}
|
||||
|
||||
getClassName() {
|
||||
return 'node ' + super.getClassName() + (this.props.node.isSelected() ? this.bem('--selected') : '');
|
||||
}
|
||||
@@ -67,16 +64,22 @@ export class NodeWidget extends BaseWidget<NodeProps> {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
ref={this.ref}
|
||||
{...this.getProps()}
|
||||
data-nodeid={this.props.node.getID()}
|
||||
style={{
|
||||
top: this.props.node.getY(),
|
||||
left: this.props.node.getX()
|
||||
}}>
|
||||
{this.props.diagramEngine.generateWidgetForNode(this.props.node)}
|
||||
</div>
|
||||
<PeformanceWidget serialized={this.props.node.serialize()}>
|
||||
{() => {
|
||||
return (
|
||||
<div
|
||||
ref={this.ref}
|
||||
{...this.getProps()}
|
||||
data-nodeid={this.props.node.getID()}
|
||||
style={{
|
||||
top: this.props.node.getY(),
|
||||
left: this.props.node.getX()
|
||||
}}>
|
||||
{this.props.diagramEngine.generateWidgetForNode(this.props.node)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</PeformanceWidget>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
23
lib-core/src/widgets/PeformanceWidget.tsx
Normal file
23
lib-core/src/widgets/PeformanceWidget.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import * as React from 'react';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
export interface PeformanceWidgetProps {
|
||||
children: () => JSX.Element;
|
||||
serialized: object;
|
||||
}
|
||||
|
||||
export interface PeformanceWidgetState {}
|
||||
|
||||
export class PeformanceWidget extends React.Component<PeformanceWidgetProps, PeformanceWidgetState> {
|
||||
shouldComponentUpdate(
|
||||
nextProps: Readonly<PeformanceWidgetProps>,
|
||||
nextState: Readonly<PeformanceWidgetState>,
|
||||
nextContext: any
|
||||
): boolean {
|
||||
return !_.isEqual(this.props.serialized, nextProps.serialized);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.children();
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace S {
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
font-family: sans-serif;
|
||||
user-select: none;
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user