@gravity-ui/graph
Version:
Modern graph editor component
122 lines (121 loc) • 4.37 kB
JavaScript
import { isAllowChangeBlockGeometry, isMetaKeyEvent } from "../../../utils/functions";
import { layoutText } from "../../../utils/renderers/text";
import { ESelectionStrategy } from "../../../utils/types/types";
import { GraphComponent } from "../GraphComponent";
const defaultStyle = {
background: "rgba(100, 100, 100, 0.1)",
border: "rgba(100, 100, 100, 0.3)",
borderWidth: 2,
selectedBackground: "rgba(100, 100, 100, 1)",
selectedBorder: "rgba(100, 100, 100, 1)",
};
const defaultGeometry = {
padding: [20, 20, 20, 20],
};
export class Group extends GraphComponent {
static define(config) {
return class SpecificGroup extends Group {
constructor(props, parent) {
super({
...props,
style: {
...defaultStyle,
...config.style,
...props.style,
},
geometry: {
...defaultGeometry,
...config.geometry,
...props.geometry,
},
}, parent);
}
};
}
get zIndex() {
return 0;
}
constructor(props, parent) {
super(props, parent);
this.blocks = [];
this.cursor = "pointer";
this.style = {
...defaultStyle,
...props.style,
};
this.geometry = {
...defaultGeometry,
...props.geometry,
};
this.subscribeToGroup();
this.addEventListener("click", (event) => {
event.stopPropagation();
this.groupState.setSelection(true, !isMetaKeyEvent(event) ? ESelectionStrategy.REPLACE : ESelectionStrategy.APPEND);
});
this.onDrag({
isDraggable: () => this.isDraggable(),
onDragUpdate: ({ diffX, diffY }) => {
const rect = {
x: this.state.rect.x - diffX,
y: this.state.rect.y - diffY,
width: this.state.rect.width,
height: this.state.rect.height,
};
this.setState({
rect,
});
this.updateHitBox(rect);
this.props.onDragUpdate(this.props.id, { diffX, diffY });
},
});
}
isDraggable() {
return (this.props.draggable &&
isAllowChangeBlockGeometry(this.context.graph.rootStore.settings.getConfigFlag("canChangeBlockGeometry"), this.state.selected));
}
getRect(rect = this.state.rect) {
const [paddingTop, paddingRight, paddingBottom, paddingLeft] = this.geometry.padding;
return {
x: rect.x - paddingLeft,
y: rect.y - paddingTop,
width: rect.width + paddingLeft + paddingRight,
height: rect.height + paddingTop + paddingBottom,
};
}
subscribeToGroup() {
this.groupState = this.context.graph.rootStore.groupsList.getGroupState(this.props.id);
return this.subscribeSignal(this.groupState.$state, (group) => {
if (group) {
this.setState({
...this.state,
...group,
});
this.updateHitBox(this.getRect(group.rect));
}
});
}
updateHitBox(rect) {
this.setHitBox(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
}
layoutText(text, textParams) {
const currentRect = this.getRect();
return layoutText(text, this.context.ctx, currentRect, {
maxWidth: currentRect.width,
maxHeight: currentRect.height,
...textParams,
});
}
renderBody(ctx, rect = this.getRect()) {
ctx.strokeStyle = this.state.selected ? this.style.selectedBorder : this.style.border;
ctx.fillStyle = this.state.selected ? this.style.selectedBackground : this.style.background;
ctx.lineWidth = this.style.borderWidth;
// Рисуем прямоугольник группы
ctx.beginPath();
ctx.roundRect(rect.x, rect.y, rect.width, rect.height, 8);
ctx.fill();
ctx.stroke();
}
render() {
this.renderBody(this.context.ctx, this.getRect());
}
}