UNPKG

graph-explorer

Version:

Graph Explorer can be used to explore and RDF graphs in SPARQL endpoints or on the web.

140 lines (126 loc) 4.18 kB
import { ElementModel, ElementIri, LinkModel, sameLink } from "../data/model"; import { Element, Link, FatLinkType } from "./elements"; import { Vector, isPolylineEqual } from "./geometry"; import { Command } from "./history"; import { DiagramModel } from "./model"; export class RestoreGeometry implements Command { readonly title = "Move elements and links"; constructor( private elementState: readonly { element: Element; position: Vector }[], private linkState: readonly { link: Link; vertices: readonly Vector[]; }[] ) {} static capture(model: DiagramModel) { return RestoreGeometry.captureElementsAndLinks(model.elements, model.links); } private static captureElementsAndLinks( elements: readonly Element[], links: readonly Link[] ) { return new RestoreGeometry( elements.map((element) => ({ element, position: element.position })), links.map((link) => ({ link, vertices: link.vertices })) ); } hasChanges() { return this.elementState.length > 0 || this.linkState.length > 0; } filterOutUnchanged(): RestoreGeometry { return new RestoreGeometry( this.elementState.filter( ({ element, position }) => !Vector.equals(element.position, position) ), this.linkState.filter( ({ link, vertices }) => !isPolylineEqual(link.vertices, vertices) ) ); } invoke(): RestoreGeometry { const previous = RestoreGeometry.captureElementsAndLinks( this.elementState.map((state) => state.element), this.linkState.map((state) => state.link) ); // restore in reverse order to workaround position changed event // handling in EmbeddedLayer inside nested elements // (child's position change causes group to resize or move itself) for (const { element, position } of [...this.elementState].reverse()) { element.setPosition(position); } for (const { link, vertices } of this.linkState) { link.setVertices(vertices); } return previous; } } export function restoreCapturedLinkGeometry(link: Link): Command { const vertices = link.vertices; return Command.create("Change link vertices", () => { const capturedInverse = restoreCapturedLinkGeometry(link); link.setVertices(vertices); return capturedInverse; }); } export function setElementExpanded( element: Element, expanded: boolean ): Command { const title = expanded ? "Expand element" : "Collapse element"; return Command.create(title, () => { element.setExpanded(expanded); return setElementExpanded(element, !expanded); }); } export function changeLinkTypeVisibility(params: { linkType: FatLinkType; visible: boolean; showLabel: boolean; preventLoading?: boolean; }): Command { const { linkType, visible, showLabel, preventLoading } = params; return Command.create("Change link type visibility", () => { const previousVisible = linkType.visible; const previousShowLabel = linkType.showLabel; linkType.setVisibility({ visible, showLabel, preventLoading }); return changeLinkTypeVisibility({ linkType, visible: previousVisible, showLabel: previousShowLabel, preventLoading, }); }); } export function setElementData( model: DiagramModel, target: ElementIri, data: ElementModel ): Command { const elements = model.elements.filter((el) => el.iri === target); const previous = elements.length > 0 ? elements[0].data : undefined; return Command.create("Set element data", () => { for (const element of model.elements.filter((el) => el.iri === target)) { element.setData(data); } return setElementData(model, data.id, previous); }); } export function setLinkData( model: DiagramModel, oldData: LinkModel, newData: LinkModel ): Command { if (!sameLink(oldData, newData)) { throw new Error( "Cannot change typeId, sourceId or targetId when changing link data" ); } return Command.create("Set link data", () => { for (const link of model.links) { if (sameLink(link.data, oldData)) { link.setData(newData); } } return setLinkData(model, newData, oldData); }); }