@gravity-ui/graph
Version:
Modern graph editor component
146 lines (145 loc) • 5.65 kB
JavaScript
import { batch, computed, signal } from "@preact/signals-core";
import { selectBlockById } from "../../store/block/selectors";
import { ESelectionStrategy } from "../../utils/types/types";
import { ConnectionState } from "./ConnectionState";
export class ConnectionsStore {
constructor(rootStore, graph) {
this.rootStore = rootStore;
this.graph = graph;
this.$connections = computed(() => {
return Array.from(this.$connectionsMap.value.values());
});
this.$connectionsMap = signal(new Map());
this.selectedConnections = new Set();
this.$selectedConnections = computed(() => {
return new Set(this.$connections.value.filter((connection) => connection.isSelected()));
});
}
getBlock(id) {
return selectBlockById(this.graph, id);
}
setSelection(connection, selected, params) {
const state = connection instanceof ConnectionState ? connection : this.$connectionsMap.value.get(connection);
if (state) {
if (selected !== Boolean(state.$state.value.selected)) {
if (!params?.ignoreChange) {
state.updateConnection({
selected,
});
}
return true;
}
}
return false;
}
updateConnections(connections) {
this.$connectionsMap.value = connections.reduce((acc, connection) => {
const c = this.getOrCreateConnection(connection);
acc.set(c.id, c);
return acc;
}, this.$connectionsMap.value);
}
setConnections(connections) {
this.$connectionsMap.value = new Map(connections.map((connection) => {
const c = this.getOrCreateConnection(connection);
return [c.id, c];
}));
}
getOrCreateConnection(connections) {
const id = ConnectionState.getConnectionId(connections);
if (this.$connectionsMap.value.has(id)) {
const c = this.$connectionsMap.value.get(id);
c.updateConnection(connections);
return c;
}
return new ConnectionState(this, connections);
}
addConnection(connection) {
const newConnection = new ConnectionState(this, connection);
this.$connectionsMap.value.set(newConnection.id, newConnection);
this.notifyConnectionMapChanged();
return newConnection.id;
}
notifyConnectionMapChanged() {
this.$connectionsMap.value = new Map(this.$connectionsMap.value);
}
deleteConnections(connections) {
connections.forEach((c) => {
this.$connectionsMap.value.delete(c.id);
});
this.notifyConnectionMapChanged();
}
deleteSelectedConnections() {
this.$connections.value.forEach((c) => {
if (c.$state.value.selected) {
this.$connectionsMap.value.delete(c.id);
}
});
this.notifyConnectionMapChanged();
}
computeSelectionChange(ids, selected, strategy = ESelectionStrategy.REPLACE) {
const list = new Set(this.$selectedConnections.value);
let add;
let removed;
if (!selected) {
removed = new Set(this.getConnections(ids).filter((connection) => {
if (this.setSelection(connection, false, { ignoreChange: true })) {
list.delete(connection);
return true;
}
return false;
}));
}
else {
if (strategy === ESelectionStrategy.REPLACE) {
removed = new Set(Array.from(this.$selectedConnections.value).filter((connection) => {
return this.setSelection(connection, false, { ignoreChange: true });
}));
list.clear();
}
add = new Set(this.getConnections(ids).filter((connection) => {
if (this.setSelection(connection.id, true, { ignoreChange: true }) ||
strategy === ESelectionStrategy.REPLACE) {
removed?.delete(connection);
list.add(connection);
return true;
}
return false;
}));
}
return { add: Array.from(add || []), removed: Array.from(removed || []), list: Array.from(list) };
}
setConnectionsSelection(ids, selected, strategy = ESelectionStrategy.REPLACE) {
const { add, removed, list } = this.computeSelectionChange(ids, selected, strategy);
if (add.length || removed.length) {
this.graph.executеDefaultEventAction("connection-selection-change", {
list: list.map((c) => c.asTConnection()),
changes: {
add: add.map((c) => c.asTConnection()),
removed: removed.map((c) => c.asTConnection()),
},
}, () => {
batch(() => {
removed.forEach((c) => this.setSelection(c.id, false));
add.forEach((c) => this.setSelection(c.id, true));
});
});
}
}
toJSON() {
return this.$connections.value.map((c) => c.asTConnection());
}
resetSelection() {
this.setConnectionsSelection([], false);
}
getConnections(ids) {
if (!ids || !ids.length) {
return this.$connections.value;
}
const map = this.$connectionsMap.value;
return ids.map((id) => map.get(id)).filter(Boolean);
}
reset() {
this.setConnections([]);
}
}