This repository has been archived by the owner on Jul 31, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7a62260
commit aa96d8b
Showing
10 changed files
with
717 additions
and
664 deletions.
There are no files selected for viewing
110 changes: 110 additions & 0 deletions
110
packages/flow-lineage/src/components/f-dag/add-group.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { html } from "lit"; | ||
import type { FDag } from "./f-dag"; | ||
import type { FInput, FSelect, FTabNode } from "@ollion/flow-core"; | ||
|
||
export function addGroupPopover(this: FDag) { | ||
return html` <f-popover size="small" id="add-group-popover" .overlay=${false} target="#add-group"> | ||
<f-div @wheel=${(e: Event) => e.stopPropagation()}> | ||
<f-tab> | ||
<f-tab-node | ||
@click=${this.switchTab} | ||
class="gr-selection-tabs" | ||
active | ||
content-id=${`existing-group-selection`} | ||
> | ||
<f-div width="100%" height="100%" align="middle-center" direction="column"> | ||
Exisiting | ||
</f-div> | ||
</f-tab-node> | ||
<f-tab-node @click=${this.switchTab} class="gr-selection-tabs" content-id=${`new-group`}> | ||
<f-div width="100%" height="100%" align="middle-center" direction="column"> | ||
Create New | ||
</f-div> | ||
</f-tab-node> | ||
</f-tab> | ||
<f-tab-content id="existing-group-selection"> | ||
<f-div padding="medium" gap="medium"> | ||
<f-select | ||
id="f-group-dropdown" | ||
placeholder="Select Group" | ||
@input=${this.addToGroup} | ||
.options=${this.config.groups.map(g => g.id)} | ||
></f-select> | ||
</f-div> | ||
</f-tab-content> | ||
<f-tab-content id="new-group"> | ||
<f-div direction="column"> | ||
<f-div padding="medium" gap="medium"> | ||
<f-input id="new-group-id" placeholder="New Group Id"></f-input> | ||
<f-input id="new-group-label" placeholder="New Group Label"></f-input> | ||
</f-div> | ||
<f-div> | ||
<f-button variant="block" label="Add" @click=${this.addToNewGroup}></f-button> | ||
</f-div> | ||
</f-div> | ||
</f-tab-content> | ||
</f-div> | ||
</f-popover>`; | ||
} | ||
|
||
export function handleAddGroup(this: FDag) { | ||
this.addGroupPopoverRef.open = true; | ||
} | ||
|
||
export function addSelectionToGroup(this: FDag, groupid: string) { | ||
this.selectedNodes.forEach(sn => { | ||
sn.group = groupid; | ||
}); | ||
|
||
this.addGroupPopoverRef.open = false; | ||
|
||
this.config.nodes.forEach(n => { | ||
n.x = undefined; | ||
n.y = undefined; | ||
}); | ||
this.config.groups.forEach(n => { | ||
n.x = undefined; | ||
n.y = undefined; | ||
}); | ||
|
||
this.config.links.forEach(l => { | ||
l.from.x = undefined; | ||
l.from.y = undefined; | ||
l.to.x = undefined; | ||
l.to.y = undefined; | ||
}); | ||
|
||
this.selectedNodes = []; | ||
this.addGroupButton.style.display = "none"; | ||
this.requestUpdate(); | ||
} | ||
|
||
export function addToNewGroup(this: FDag) { | ||
const groupIdInput = this.querySelector<FInput>("#new-group-id")!; | ||
const groupLabelInput = this.querySelector<FInput>("#new-group-label")!; | ||
|
||
this.config.groups.push({ | ||
id: groupIdInput.value as string, | ||
label: groupLabelInput.value as string, | ||
icon: "i-org" | ||
}); | ||
|
||
this.addSelectionToGroup(groupIdInput.value as string); | ||
} | ||
|
||
export function addToGroup(this: FDag) { | ||
const groupDropdown = this.querySelector<FSelect>(`#f-group-dropdown`)!; | ||
const groupid = groupDropdown.value as string; | ||
|
||
this.addSelectionToGroup(groupid); | ||
} | ||
|
||
export function switchTab(this: FDag, event: PointerEvent) { | ||
const tabNodeElement = event.currentTarget as FTabNode; | ||
|
||
this.groupSelectionTabs.forEach(tab => { | ||
tab.active = false; | ||
}); | ||
tabNodeElement.active = true; | ||
} |
22 changes: 22 additions & 0 deletions
22
packages/flow-lineage/src/components/f-dag/background-svg.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { html } from "lit"; | ||
|
||
export default function backgroundSVG() { | ||
return html` <svg | ||
class="background-svg" | ||
style="position: absolute;width: 100%;height: 100%;top: 0px;left: 0px;" | ||
> | ||
<pattern | ||
class="background-pattern" | ||
id="pattern-1undefined" | ||
x="0" | ||
y="0" | ||
width="24" | ||
height="24" | ||
patternUnits="userSpaceOnUse" | ||
patternTransform="translate(-0.5,-0.5)" | ||
> | ||
<circle cx="0.5" cy="0.5" r="1" fill="var(--color-border-subtle)"></circle> | ||
</pattern> | ||
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-1undefined)"></rect> | ||
</svg>`; | ||
} |
242 changes: 242 additions & 0 deletions
242
packages/flow-lineage/src/components/f-dag/compute-placement.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
import type { FDag } from "./f-dag"; | ||
import buildHierarchy from "./hierarchy-builder"; | ||
import { | ||
CustomPlacementByElement, | ||
CustomPlacementBySection, | ||
FDagElement, | ||
FDagGroup, | ||
HierarchyNode | ||
} from "./types"; | ||
|
||
export default function computePlacement(this: FDag) { | ||
this.groupsHTML = []; | ||
this.nodesHTML = []; | ||
const { roots: rootNodes, customPlacements } = buildHierarchy(this.config); | ||
|
||
const positionNodes = ( | ||
containerId: string, | ||
elements: HierarchyNode[], | ||
x: number, | ||
y: number, | ||
isCollapsed: boolean, | ||
spaceX = 100, | ||
spaceY = 100 | ||
) => { | ||
const elementIds = elements.map(e => e.id); | ||
const conatinerElementObject = this.getElement(containerId) as FDagGroup; | ||
const layoutDirection = (() => { | ||
if (containerId === "root") { | ||
return this.config.layoutDirection; | ||
} | ||
if (conatinerElementObject.layoutDirection === "vertical") { | ||
return "horizontal"; | ||
} | ||
return "vertical"; | ||
})(); | ||
const nodeLinks = this.config.links.filter( | ||
l => elementIds.includes(l.from.elementId) && elementIds.includes(l.to.elementId) | ||
); | ||
const roots = new Set<HierarchyNode>(elements); | ||
const nonroots = new Set<HierarchyNode>(); | ||
nodeLinks.forEach(link => { | ||
const fromElement = elements.find(e => e.id === link.from.elementId)!; | ||
if (!nonroots.has(fromElement)) { | ||
roots.add(fromElement); | ||
} | ||
if (!fromElement.next) { | ||
fromElement.next = []; | ||
} | ||
|
||
const toElement = elements.find(e => e.id === link.to.elementId)!; | ||
if (roots.has(toElement)) { | ||
roots.delete(toElement); | ||
} | ||
nonroots.add(toElement); | ||
fromElement.next.push(toElement); | ||
}); | ||
|
||
const initialY = y; | ||
const initialX = x; | ||
let maxX = 0; | ||
let maxY = 0; | ||
const minX = x; | ||
const minY = y; | ||
let section = 0; | ||
const calculateCords = (ns: HierarchyNode[]) => { | ||
const nexts: HierarchyNode[] = []; | ||
let maxWidth = this.defaultElementWidth; | ||
let maxHeight = this.defaultElementHeight; | ||
section += 1; | ||
const nextSection = () => { | ||
if (!isCollapsed) { | ||
if (layoutDirection === "vertical") { | ||
y += maxHeight + spaceY; | ||
x = initialX; | ||
} else { | ||
x += maxWidth + spaceX; | ||
y = initialY; | ||
} | ||
} | ||
}; | ||
|
||
let currentNodeId: string | null; | ||
const isElementPlacement = (elementObject: FDagElement) => | ||
elementObject.placement && | ||
(elementObject.placement as CustomPlacementByElement).elementId === currentNodeId; | ||
const isSectionPlacement = (elementObject: FDagElement) => | ||
elementObject.placement && | ||
(elementObject.placement as CustomPlacementBySection).section === section && | ||
containerId === "root"; | ||
const placeElement = (n: HierarchyNode) => { | ||
const elementObject = this.getElement(n.id); | ||
if ( | ||
!elementObject.placement || | ||
isSectionPlacement(elementObject) || | ||
isElementPlacement(elementObject) | ||
) { | ||
const customPlacementsByElements = this.getCustomPlacementElementsByElementId( | ||
elementObject.id, | ||
customPlacements | ||
); | ||
if (customPlacementsByElements.length > 0) { | ||
currentNodeId = elementObject.id; | ||
} | ||
const beforeCustomElements = customPlacementsByElements.filter( | ||
c => c?.placement?.position === "before" | ||
); | ||
const afterCustomElements = customPlacementsByElements.filter( | ||
c => c?.placement?.position === "after" | ||
); | ||
beforeCustomElements.forEach(b => { | ||
if (b) placeElement(b); | ||
}); | ||
|
||
if (elementObject.x === undefined) { | ||
elementObject.x = x; | ||
} else { | ||
x = elementObject.x; | ||
} | ||
if (elementObject.y === undefined) { | ||
elementObject.y = y; | ||
} else { | ||
y = elementObject.y; | ||
} | ||
|
||
if (n.type === "group" && n.children && n.children.length > 0) { | ||
const isCollapseRequired = | ||
isCollapsed || Boolean((elementObject as FDagGroup).collapsed); | ||
const { width, height } = positionNodes( | ||
n.id, | ||
n.children, | ||
isCollapseRequired ? x : x + 20, | ||
isCollapseRequired ? y : y + 60, | ||
isCollapseRequired, | ||
(elementObject as FDagGroup).spacing?.x, | ||
(elementObject as FDagGroup).spacing?.y | ||
); | ||
if (isCollapsed) { | ||
elementObject.hidden = true; | ||
} else { | ||
elementObject.hidden = false; | ||
} | ||
elementObject.width = width < 150 ? 150 : width; | ||
elementObject.height = height + (isCollapseRequired ? 0 : 20); | ||
} else if (isCollapsed) { | ||
elementObject.hidden = true; | ||
} else { | ||
elementObject.hidden = false; | ||
} | ||
|
||
if (!elementObject.width) { | ||
elementObject.width = this.defaultElementWidth; | ||
} | ||
if (!elementObject.height) { | ||
elementObject.height = this.defaultElementHeight; | ||
} | ||
|
||
if (n.type === "group") { | ||
this.groupsHTML.push(this.getNodeGroupTemplate(elementObject, "group")); | ||
} else { | ||
this.nodesHTML.push(this.getNodeGroupTemplate(elementObject)); | ||
} | ||
|
||
if (x + elementObject.width > maxX) { | ||
maxX = x + elementObject.width; | ||
} | ||
if (y + elementObject.height > maxY) { | ||
maxY = y + elementObject.height; | ||
} | ||
|
||
if (!isCollapsed) { | ||
if (layoutDirection === "vertical") { | ||
x += elementObject.width + spaceX; | ||
} else { | ||
y += elementObject.height + spaceY; | ||
} | ||
} | ||
|
||
if (elementObject.width > maxWidth) { | ||
maxWidth = elementObject.width; | ||
} | ||
if (elementObject.height > maxHeight) { | ||
maxHeight = elementObject.height; | ||
} | ||
afterCustomElements.forEach(b => { | ||
if (b) placeElement(b); | ||
}); | ||
currentNodeId = null; | ||
if (n.next) nexts.push(...n.next); | ||
} | ||
}; | ||
const customPlacementsElements = | ||
containerId === "root" ? this.getCustomPlacementElements(section, customPlacements) : []; | ||
|
||
const beforeElements = | ||
containerId === "root" | ||
? customPlacementsElements.filter(c => c?.placement?.position === "before") | ||
: []; | ||
const afterElements = | ||
containerId === "root" | ||
? customPlacementsElements.filter(c => c?.placement?.position === "after") | ||
: []; | ||
beforeElements.forEach(b => { | ||
if (b) placeElement(b); | ||
}); | ||
|
||
if (beforeElements.length > 0) { | ||
nextSection(); | ||
maxHeight = this.defaultElementHeight; | ||
maxWidth = this.defaultElementWidth; | ||
} | ||
|
||
const skipTheseElements = [...beforeElements, ...afterElements].map(ba => ba?.id); | ||
ns.filter(n => !skipTheseElements.includes(n.id)).forEach(placeElement); | ||
|
||
if (afterElements.length > 0) { | ||
nextSection(); | ||
maxHeight = this.defaultElementHeight; | ||
maxWidth = this.defaultElementWidth; | ||
} | ||
afterElements.forEach(b => { | ||
if (b) placeElement(b); | ||
}); | ||
nextSection(); | ||
|
||
if (nexts.length > 0) calculateCords(nexts); | ||
}; | ||
calculateCords(Array.from(roots)); | ||
if (isCollapsed) { | ||
return { | ||
width: this.collapsedNodeWidth, | ||
height: this.collapsedNodeHeight | ||
}; | ||
} | ||
|
||
return { | ||
width: maxX - minX + 40, | ||
height: maxY - minY + 60 | ||
}; | ||
}; | ||
|
||
positionNodes("root", rootNodes, 0, 0, false, this.config.spacing?.x, this.config.spacing?.y); | ||
} |
File renamed without changes.
File renamed without changes.
Oops, something went wrong.