From 352f235610113459f9a0870a58a7521fa9e7ef1a Mon Sep 17 00:00:00 2001 From: barsdeveloper Date: Wed, 22 Dec 2021 22:24:13 +0100 Subject: [PATCH] Graph link work in progress --- dist/ueblueprint.js | 330 ++++++++++++++++++++++---------- index.html | 2 +- js/Blueprint.js | 47 +++-- js/graph/GraphElement.js | 3 + js/graph/GraphLink.js | 59 +++++- js/graph/GraphNode.js | 19 +- js/graph/GraphPin.js | 18 ++ js/graph/SelectableDraggable.js | 37 ++-- js/input/Context.js | 1 + js/input/DragLink.js | 8 +- js/input/KeyboardCanc.js | 2 +- js/input/Paste.js | 2 +- js/template/LinkTemplate.js | 28 +++ js/template/NodeTemplate.js | 2 +- 14 files changed, 399 insertions(+), 159 deletions(-) diff --git a/dist/ueblueprint.js b/dist/ueblueprint.js index 48b0446..0c50009 100644 --- a/dist/ueblueprint.js +++ b/dist/ueblueprint.js @@ -322,6 +322,9 @@ class GraphElement extends HTMLElement { this.blueprint = this.closest("ueb-blueprint"); this.template.apply(this); } + + disconnectedCallback() { + } } document.createElement("div"); @@ -334,7 +337,7 @@ const tagReplacement = { '"': '"' }; -function sanitizeText(value) { +function sanitizeText$1(value) { if (value.constructor === String) { return value.replace(/[&<>'"]/g, tag => tagReplacement[tag]) } @@ -386,11 +389,11 @@ class SelectorTemplate extends Template { */ applyStartSelecting(selector, initialPosition) { // Set initial position - selector.style.setProperty("--ueb-select-from-x", sanitizeText(initialPosition[0])); - selector.style.setProperty("--ueb-select-from-y", sanitizeText(initialPosition[1])); + selector.style.setProperty("--ueb-select-from-x", sanitizeText$1(initialPosition[0])); + selector.style.setProperty("--ueb-select-from-y", sanitizeText$1(initialPosition[1])); // Final position coincide with the initial position, at the beginning of selection - selector.style.setProperty("--ueb-select-to-x", sanitizeText(initialPosition[0])); - selector.style.setProperty("--ueb-select-to-y", sanitizeText(initialPosition[1])); + selector.style.setProperty("--ueb-select-to-x", sanitizeText$1(initialPosition[0])); + selector.style.setProperty("--ueb-select-to-y", sanitizeText$1(initialPosition[1])); selector.dataset.selecting = "true"; } @@ -399,8 +402,8 @@ class SelectorTemplate extends Template { * @param {GraphSelector} selector Selector element */ applyDoSelecting(selector, finalPosition) { - selector.style.setProperty("--ueb-select-to-x", sanitizeText(finalPosition[0])); - selector.style.setProperty("--ueb-select-to-y", sanitizeText(finalPosition[1])); + selector.style.setProperty("--ueb-select-to-x", sanitizeText$1(finalPosition[0])); + selector.style.setProperty("--ueb-select-to-y", sanitizeText$1(finalPosition[1])); } /** @@ -477,10 +480,10 @@ class BlueprintTemplate extends Template {
@@ -522,8 +525,8 @@ class BlueprintTemplate extends Template { * @param {Blueprint} brueprint The blueprint element */ applyZoom(blueprint, newZoom) { - blueprint.classList.remove("ueb-zoom-" + sanitizeText(blueprint.zoom)); - blueprint.classList.add("ueb-zoom-" + sanitizeText(newZoom)); + blueprint.classList.remove("ueb-zoom-" + sanitizeText$1(blueprint.zoom)); + blueprint.classList.add("ueb-zoom-" + sanitizeText$1(newZoom)); } /** @@ -531,8 +534,8 @@ class BlueprintTemplate extends Template { * @param {Blueprint} brueprint The blueprint element */ applyExpand(blueprint) { - blueprint.gridElement.style.setProperty("--ueb-additional-x", sanitizeText(blueprint.additional[0])); - blueprint.gridElement.style.setProperty("--ueb-additional-y", sanitizeText(blueprint.additional[1])); + blueprint.gridElement.style.setProperty("--ueb-additional-x", sanitizeText$1(blueprint.additional[0])); + blueprint.gridElement.style.setProperty("--ueb-additional-y", sanitizeText$1(blueprint.additional[1])); } /** @@ -540,8 +543,8 @@ class BlueprintTemplate extends Template { * @param {Blueprint} brueprint The blueprint element */ applyTranlate(blueprint) { - blueprint.gridElement.style.setProperty("--ueb-translate-x", sanitizeText(blueprint.translateValue[0])); - blueprint.gridElement.style.setProperty("--ueb-translate-y", sanitizeText(blueprint.translateValue[1])); + blueprint.gridElement.style.setProperty("--ueb-translate-x", sanitizeText$1(blueprint.translateValue[0])); + blueprint.gridElement.style.setProperty("--ueb-translate-y", sanitizeText$1(blueprint.translateValue[1])); } } @@ -563,6 +566,7 @@ class Context { } unlistenDOMElement() { + this.blueprintUnfocused(); this.blueprint.removeEventListener("blueprintfocus", this.blueprintfocusHandler); this.blueprint.removeEventListener("blueprintunfocus", this.blueprintunfocusHandler); } @@ -1511,7 +1515,7 @@ class KeyvoardCanc extends KeyboardShortcut { } fire() { - this.blueprint.deleteNode(...this.blueprint.getNodes(true)); + this.blueprint.removeGraphElement(...this.blueprint.getNodes(true)); } } @@ -1550,11 +1554,11 @@ class PinTemplate extends Template { if (pin.isInput()) { return html` - ${sanitizeText(pin.getPinDisplayName())} + ${sanitizeText$1(pin.getPinDisplayName())} ` } else { return html` - ${sanitizeText(pin.getPinDisplayName())} + ${sanitizeText$1(pin.getPinDisplayName())} ` } @@ -1566,7 +1570,7 @@ class PinTemplate extends Template { */ apply(pin) { super.apply(pin); - pin.classList.add("ueb-node-" + pin.isInput() ? "input" : "output", "ueb-node-value-" + sanitizeText(pin.getType())); + pin.classList.add("ueb-node-" + pin.isInput() ? "input" : "output", "ueb-node-value-" + sanitizeText$1(pin.getType())); pin.clickableElement = pin.querySelector(".ueb-node-value-icon"); } } @@ -1575,11 +1579,15 @@ class DragLink extends MouseClickDrag { constructor(target, blueprint, options) { super(target, blueprint, options); + /** @type {import("../graph/GraphPin").default} */ + this.target; + /** @type {import("../graph/GraphLink").default} */ + this.link; } startDrag() { - let a = 12; - console.log(a); + this.target.dragLink(); + } dragTo(location, movement) { @@ -1591,6 +1599,112 @@ class DragLink extends MouseClickDrag { } } +/** + * @typedef {import("../graph/GraphLink").default} GraphLink + */ +class LinkTemplate extends Template { + + /** + * Computes the html content of the target element. + * @param {GraphLink} link Link connecting two graph nodes + * @returns The result html + */ + render(link) { + return html` + + + + ` + } + + /** + * Applies the style to the element. + * @param {GraphLink} link Element of the graph + */ + apply(link) { + super.apply(link); + + } + + /** + * Applies the style relative to the source pin location. + * @param {GraphLink} link Link element + */ + applySourceLocation(link, initialPosition) { + // Set initial position + link.style.setProperty("--ueb-link-from-x", sanitizeText(initialPosition[0])); + link.style.setProperty("--ueb-link-from-y", sanitizeText(initialPosition[1])); + } + + /** + * Applies the style relative to the destination pin location. + * @param {GraphLink} link Link element + */ + applyDestinationLocation(link, finalPosition) { + link.style.setProperty("--ueb-link-to-x", sanitizeText(finalPosition[0])); + link.style.setProperty("--ueb-link-to-y", sanitizeText(finalPosition[1])); + } +} + +/** + * @type {import("./GraphPin").default} GraphPin + */ +class GraphLink extends GraphElement { + + /** @type {GraphPin} */ + #source + /** @type {GraphPin} */ + #destination + #nodeDeleteHandler = _ => this.blueprint.removeGraphElement(this) + #nodeDragSourceHandler = _ => this.setSourceLocation(this.#source.getLinkLocation()) + #nodeDragDestinatonHandler = _ => this.setDestinationLocation(this.#destination.getLinkLocation()) + + /** + * @param {?GraphPin} source + * @param {?GraphPin} destination + */ + constructor(source, destination) { + super(this, new LinkTemplate()); + /** @type {import("../template/LinkTemplate").default} */ + this.template; + this.setSource(source); + this.setDestination(destination); + } + + setSourceLocation(location) { + this.template.applySourceLocation(this.#source.getLinkLocation()); + } + + setDestinationLocation(location) { + this.template.applyDestinationLocation(this.#destination.getLinkLocation()); + } + + /** + * @param {GraphPin} graphPin + */ + setSourcePin(graphPin) { + this.#source?.removeEventListener("ueb-node-delete", this.#nodeDeleteHandler); + this.#source?.removeEventListener("ueb-node-drag", this.#nodeDragSourceHandler); + this.#source = graphPin; + this.#source?.addEventListener("ueb-node-delete", this.#nodeDeleteHandler); + this.#source?.addEventListener("ueb-node-drag", this.#nodeDragSourceHandler); + } + + /** + * + * @param {GraphPin} graphPin + */ + setDestinationPin(graphPin) { + this.#destination?.removeEventListener("ueb-node-delete", this.#nodeDeleteHandler); + this.#destination?.removeEventListener("ueb-node-drag", this.#nodeDragDestinatonHandler); + this.#destination = graphPin; + this.#destination?.addEventListener("ueb-node-delete", this.#nodeDeleteHandler); + this.#destination?.addEventListener("ueb-node-drag", this.#nodeDragDestinatonHandler); + } +} + +customElements.define("ueb-link", GraphLink); + class GraphPin extends GraphElement { constructor(entity) { @@ -1635,6 +1749,23 @@ class GraphPin extends GraphElement { getType() { return this.entity.getType() } + + /** + * + * @returns {GraphLink} The link created + */ + dragLink() { + let link = new GraphLink(this); + return link + } + + /** + * Returns The exact location where the link originates from or arrives at. + * @returns {Number[]} The location array + */ + getLinkLocation() { + return [0, 0]; + } } customElements.define("ueb-pin", GraphPin); @@ -1649,8 +1780,8 @@ class SelectableDraggableTemplate extends Template { * @param {SelectableDraggable} element Element of the graph */ applyLocation(element) { - element.style.setProperty("--ueb-position-x", sanitizeText(element.location[0])); - element.style.setProperty("--ueb-position-y", sanitizeText(element.location[1])); + element.style.setProperty("--ueb-position-x", sanitizeText$1(element.location[0])); + element.style.setProperty("--ueb-position-y", sanitizeText$1(element.location[1])); } /** @@ -1706,7 +1837,7 @@ class NodeTemplate extends SelectableDraggableTemplate {
- ${sanitizeText(node.entity.getNodeDisplayName())} + ${sanitizeText$1(node.entity.getNodeDisplayName())}
@@ -1719,7 +1850,7 @@ class NodeTemplate extends SelectableDraggableTemplate { } /** - * Returns the html elements rendered from this template. + * Applies the style to the element. * @param {GraphNode} node Element of the graph */ apply(node) { @@ -1727,8 +1858,8 @@ class NodeTemplate extends SelectableDraggableTemplate { if (node.selected) { node.classList.add("ueb-selected"); } - node.style.setProperty("--ueb-position-x", sanitizeText(node.location[0])); - node.style.setProperty("--ueb-position-y", sanitizeText(node.location[1])); + node.style.setProperty("--ueb-position-x", sanitizeText$1(node.location[0])); + node.style.setProperty("--ueb-position-y", sanitizeText$1(node.location[1])); /** @type {HTMLElement} */ let inputContainer = node.querySelector(".ueb-node-inputs"); /** @type {HTMLElement} */ @@ -1804,6 +1935,7 @@ class SelectableDraggable extends GraphElement { } disconnectedCallback() { + super.disconnectedCallback(); this.dragObject.unlistenDOMElement(); } @@ -1816,35 +1948,33 @@ class SelectableDraggable extends GraphElement { this.setLocation([this.location[0] + value[0], this.location[1] + value[1]]); } - dispatchDragEvent(value) { - if (!this.selected) { - this.blueprint.unselectAll(); - this.setSelected(true); - } - let dragEvent = new CustomEvent("uDragSelected", { - detail: { - instigator: this, - value: value - }, - bubbles: false, - cancelable: true, - composed: false, - }); - this.blueprint.dispatchEvent(dragEvent); - } - setSelected(value = true) { if (this.selected == value) { return } this.selected = value; if (this.selected) { - this.blueprint.addEventListener("uDragSelected", this.dragHandler); + this.blueprint.addEventListener("ueb-node-drag", this.dragHandler); } else { - this.blueprint.removeEventListener("uDragSelected", this.dragHandler); + this.blueprint.removeEventListener("ueb-node-drag", this.dragHandler); } this.template.applySelected(this); } + + dispatchDragEvent(value) { + if (!this.selected) { + this.blueprint.unselectAll(); + this.setSelected(true); + } + let dragEvent = new CustomEvent("ueb-node-drag", { + detail: { + instigator: this, + value: value + }, + cancelable: true + }); + this.blueprint.dispatchEvent(dragEvent); + } } class GraphNode extends SelectableDraggable { @@ -1857,7 +1987,6 @@ class GraphNode extends SelectableDraggable { super(entity, new NodeTemplate()); /** @type {ObjectEntity} */ this.entity; - this.graphNodeName = "n/a"; this.dragLinkObjects = []; super.setLocation([this.entity.NodePosX, this.entity.NodePosY]); } @@ -1867,6 +1996,15 @@ class GraphNode extends SelectableDraggable { return new GraphNode(entity) } + connectedCallback() { + super.connectedCallback(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.dispatchDeleteEvent(); + } + /** * * @returns {PinEntity[]} @@ -1886,6 +2024,14 @@ class GraphNode extends SelectableDraggable { this.entity.NodePosY = new nodeType(value[1]); super.setLocation(value); } + + dispatchDeleteEvent(value) { + let dragEvent = new CustomEvent("ueb-node-delete", { + bubbles: true, + cancelable: true, + }); + this.dispatchEvent(dragEvent); + } } customElements.define("ueb-node", GraphNode); @@ -1921,7 +2067,7 @@ class Paste extends Context { this.blueprint.unselectAll(); } let mousePosition = this.blueprint.entity.mousePosition; - this.blueprint.addNode(...nodes); + this.blueprint.addGraphElement(...nodes); nodes.forEach(node => { const locationOffset = [ mousePosition[0] - left, @@ -2041,7 +2187,6 @@ class Zoom extends MouseWheel { } } -/** @typedef {import("./graph/GraphNode").default} GraphNode */ class Blueprint extends GraphElement { constructor() { @@ -2050,6 +2195,8 @@ class Blueprint extends GraphElement { this.template; /** @type {GraphNode[]}" */ this.nodes = []; + /** @type {GraphLink[]}" */ + this.links = []; this.expandGridSize = 400; /** @type {number[]} */ this.additional = /*[2 * this.expandGridSize, 2 * this.expandGridSize]*/[0, 0]; @@ -2330,32 +2477,42 @@ class Blueprint extends GraphElement { /** * - * @param {...GraphNode} graphNodes + * @param {...GraphElement} graphElements */ - addNode(...graphNodes) { - [...graphNodes].reduce( - (s, e) => { - s.push(e); - if (this.nodesContainerElement) { - this.nodesContainerElement.appendChild(e); - } - return s - }, - this.nodes); + addGraphElement(...graphElements) { + [...graphElements].forEach(v => { + if (v instanceof GraphNode) { + this.nodes.push(v); + this.nodesContainerElement?.appendChild(v); + } + if (v instanceof GraphLink) { + this.links.push(v); + this.nodesContainerElement?.appendChild(v); + } + }); } /** * - * @param {...GraphNode} graphNodes + * @param {...GraphElement} graphElements */ - deleteNode(...graphNodes) { - let deleteNodes = [...graphNodes]; - if (deleteNodes.length == 0) { + removeGraphElement(...graphElements) { + let deleteElements = [...graphElements]; + if (deleteElements.length == 0) { return } let currentDeleteI = 0; this.nodes = this.nodes.filter(v => { - if (v == deleteNodes[currentDeleteI]) { + if (v == deleteElements[currentDeleteI]) { + ++currentDeleteI; + v.remove(); + return false + } + return true + }); + currentDeleteI = 0; + this.links = this.links.filter(v => { + if (v == deleteElements[currentDeleteI]) { ++currentDeleteI; v.remove(); return false @@ -2380,45 +2537,6 @@ class Blueprint extends GraphElement { customElements.define("ueb-blueprint", Blueprint); -/** - * @typedef {import("../graph/GraphLink").default} GraphLink - */ -class LinkTemplate extends Template { - - /** - * Computes the html content of the target element. - * @param {GraphLink} link Link connecting two graph nodes - * @returns The result html - */ - render(link) { - return html` - - - - ` - } -} - -class GraphLink extends GraphElement { - - /** - * - * @typedef {{ - * node: String, - * pin: String - * }} PinReference - * @param {?PinReference} source - * @param {?PinReference} destination - */ - constructor(source, destination) { - super(this, new LinkTemplate()); - this.source = source; - this.destination = destination; - } -} - -customElements.define("ueb-link", GraphLink); - class GeneralSerializer extends Serializer { constructor(wrap, entityType, prefix, separator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) { diff --git a/index.html b/index.html index f44aaea..2b7cf56 100755 --- a/index.html +++ b/index.html @@ -28,7 +28,7 @@ CustomProperties Pin (PinId=E9BBB3A54DE64C213F52B2AFC8197637,PinName="ReturnValue",PinToolTip="Return Value String A new string which is the concatenation of A+B",Direction="EGPD_Output",PinType.PinCategory="string",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,) End Object`) let blueprint = new Blueprint() - blueprint.addNode(node1) + blueprint.addGraphElement(node1) document.querySelector('body').appendChild(blueprint)