Skip to content

Commit

Permalink
Merge pull request #216 from jeff-phillips-18/group-label-position
Browse files Browse the repository at this point in the history
feat(group label): Add ability to center the group's label on the edge
  • Loading branch information
jeff-phillips-18 authored Jun 11, 2024
2 parents 6718a46 + 57b04bd commit d6479b5
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 69 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ coverage
.eslintcache
generated
*.d.ts
*/css/*.js
**/css/*.js

# package managers
yarn-error.log
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const DemoTaskGroup: React.FunctionComponent<DemoTaskGroupProps> = ({ element, .
collapsedWidth={GROUP_TASK_WIDTH}
collapsedHeight={DEFAULT_TASK_HEIGHT}
element={element as Node}
centerLabelOnEdge
recreateLayoutOnCollapseChange
getEdgeCreationTypes={getEdgeCreationTypes}
scaleNode={hover && detailsLevel !== ScaleDetailsLevel.high}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export const createExecution3 = (runAfter?: string): [string, PipelineNodeModel[
height: DEFAULT_TASK_HEIGHT,
group: true,
style: {
padding: [NODE_PADDING_VERTICAL, NODE_PADDING_HORIZONTAL]
padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL]
},
runAfterTasks: [task_3_1.id],
data: {
Expand Down Expand Up @@ -386,7 +386,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [
'metadata',
'training-configurator-and-validator'
],
style: { padding: [15, 15] },
style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] },
data: {}
},
{
Expand Down Expand Up @@ -420,7 +420,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [
'model',
'model-upload'
],
style: { padding: [15, 15] },
style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] },
data: {}
},
{
Expand Down Expand Up @@ -519,7 +519,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [
'model-evaluation-import',
'table-to-uri'
],
style: { padding: [15, 15] },
style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] },
data: {}
},
{
Expand Down Expand Up @@ -748,7 +748,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [
'get-prediction-image-uri-2',
'model-upload-2'
],
style: { padding: [15, 15] },
style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] },
data: {}
},
{
Expand Down Expand Up @@ -797,7 +797,7 @@ export const createComplexDemoPipelineGroupsNodes = (): PipelineNodeModel[] => [
'model-evaluation-import-2',
'table-to-uri-2'
],
style: { padding: [15, 15] },
style: { padding: [GROUP_PADDING_VERTICAL, GROUP_PADDING_HORIZONTAL] },
data: {}
},
{
Expand Down
11 changes: 6 additions & 5 deletions packages/module/src/components/ElementWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useDndManager } from '../behavior/useDndManager';

interface ElementWrapperProps {
element: Graph | Edge | Node;
level?: number; // used for groups to set z-index keeping child groups drawn on top of their parent.
}

const NodeElementComponent: React.FunctionComponent<{ element: Node }> = observer(({ element }) => {
Expand Down Expand Up @@ -44,7 +45,7 @@ const ElementComponent: React.FunctionComponent<ElementWrapperProps> = observer(
return null;
});

const ElementChildren: React.FunctionComponent<ElementWrapperProps> = observer(({ element }) => (
const ElementChildren: React.FunctionComponent<ElementWrapperProps> = observer(({ element, level }) => (
<>
{element
.getChildren()
Expand All @@ -56,12 +57,12 @@ const ElementChildren: React.FunctionComponent<ElementWrapperProps> = observer((
.getChildren()
.filter(isNode)
.map((e) => (
<ElementWrapper key={e.getId()} element={e} />
<ElementWrapper key={e.getId()} element={e} level={level} />
))}
</>
));

const ElementWrapper: React.FunctionComponent<ElementWrapperProps> = observer(({ element }) => {
const ElementWrapper: React.FunctionComponent<ElementWrapperProps> = observer(({ element, level = 0 }) => {
if (!element.isVisible()) {
if (!isNode(element) || element.isDimensionsInitialized()) {
return null;
Expand Down Expand Up @@ -116,9 +117,9 @@ const ElementWrapper: React.FunctionComponent<ElementWrapperProps> = observer(({
);
}
return (
<g {...commonAttrs}>
<g {...commonAttrs} style={{ zIndex: level }}>
<ElementComponent element={element} />
<ElementChildren element={element} />
<ElementChildren element={element} level={level + 1} />
</g>
);
});
Expand Down
22 changes: 14 additions & 8 deletions packages/module/src/components/nodes/labels/NodeLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type NodeLabelProps = {
x?: number;
y?: number;
position?: LabelPosition;
centerLabelOnEdge?: boolean;
boxRef?: React.Ref<SVGRectElement>;
cornerRadius?: number;
status?: NodeStatus;
secondaryLabel?: string;
Expand Down Expand Up @@ -54,6 +56,7 @@ const NodeLabel: React.FunctionComponent<NodeLabelProps> = ({
x = 0,
y = 0,
position = LabelPosition.bottom,
centerLabelOnEdge,
secondaryLabel,
status,
badge,
Expand All @@ -76,6 +79,7 @@ const NodeLabel: React.FunctionComponent<NodeLabelProps> = ({
actionIcon,
actionIconClassName,
onActionIconClick,
boxRef,
...other
}) => {
const [labelHover, labelHoverRef] = useHover();
Expand Down Expand Up @@ -123,26 +127,26 @@ const NodeLabel: React.FunctionComponent<NodeLabelProps> = ({
const primaryWidth = iconSpace + badgeSpace + paddingX + textSize.width + actionSpace + contextSpace + paddingX;
const secondaryWidth = secondaryLabel && secondaryTextSize ? secondaryTextSize.width + 2 * paddingX : 0;
const width = Math.max(primaryWidth, secondaryWidth);
const backgroundHeight =
height + (secondaryLabel && secondaryTextSize ? secondaryTextSize.height + paddingY * 2 : 0);

let startX: number;
let startY: number;
if (position === LabelPosition.top) {
startX = x - width / 2;
startY = -y - height - paddingY;
startY = -y - height - (centerLabelOnEdge ? -backgroundHeight / 2 : paddingY);
} else if (position === LabelPosition.right) {
startX = x + iconSpace;
startX = x + iconSpace - (centerLabelOnEdge ? width / 2 : 0);
startY = y - height / 2;
} else if (position === LabelPosition.left) {
startX = -width - paddingX;
startY = y - height / 2 + paddingY;
startX = centerLabelOnEdge ? x - width / 2 : -width - paddingX;
startY = y - height / 2;
} else {
startX = x - width / 2 + iconSpace / 2;
startY = y;
startY = y - (centerLabelOnEdge ? backgroundHeight / 2 : 0);
}
const actionStartX = iconSpace + badgeSpace + paddingX + textSize.width + paddingX;
const contextStartX = actionStartX + actionSpace;
const backgroundHeight =
height + (secondaryLabel && secondaryTextSize ? secondaryTextSize.height + paddingY * 2 : 0);
let badgeStartX = 0;
let badgeStartY = 0;
if (badgeSize) {
Expand Down Expand Up @@ -183,6 +187,7 @@ const NodeLabel: React.FunctionComponent<NodeLabelProps> = ({
contextSize,
secondaryLabel,
secondaryTextSize,
centerLabelOnEdge,
position,
x,
y
Expand All @@ -200,8 +205,9 @@ const NodeLabel: React.FunctionComponent<NodeLabelProps> = ({
<NodeShadows />
{textSize && (
<rect
ref={boxRef}
className={css(styles.topologyNodeLabelBackground)}
key={`rect-${filterId}`} // update key to force remount on filter update
key={`rect-${filterId}-${width}`} // update key to force remount on filter or size update
filter={filterId && createSvgIdUrl(filterId)}
x={0}
y={0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { Node } from '../../../types';

export default class TaskGroupSourceAnchor extends AbstractAnchor {
private vertical = false;
private anchorOffset = 0;

constructor(owner: Node, vertical: boolean = true) {
constructor(owner: Node, vertical: boolean = true, offset: number = 0) {
super(owner);
this.vertical = vertical;
this.anchorOffset = offset;
}

getLocation(): Point {
Expand All @@ -17,8 +19,8 @@ export default class TaskGroupSourceAnchor extends AbstractAnchor {
getReferencePoint(): Point {
const bounds = this.owner.getBounds();
if (this.vertical) {
return new Point(bounds.x + bounds.width / 2, bounds.bottom());
return new Point(bounds.x + bounds.width / 2, bounds.bottom() + this.anchorOffset);
}
return new Point(bounds.right(), bounds.y + bounds.height / 2);
return new Point(bounds.right() + this.anchorOffset, bounds.y + bounds.height / 2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { Point } from '../../../geom';

export default class TaskGroupTargetAnchor extends AbstractAnchor {
private vertical = false;
private anchorOffset = 0;

constructor(owner: Node, vertical = false) {
constructor(owner: Node, vertical = false, offset: number = 0) {
super(owner);
this.vertical = vertical;
this.anchorOffset = offset;
}

getLocation(): Point {
Expand All @@ -18,8 +20,8 @@ export default class TaskGroupTargetAnchor extends AbstractAnchor {
const bounds = this.owner.getBounds();

if (this.vertical) {
return new Point(bounds.x + bounds.width / 2, bounds.y);
return new Point(bounds.x + bounds.width / 2, bounds.y - this.anchorOffset);
}
return new Point(bounds.x, bounds.y + bounds.height / 2);
return new Point(bounds.x - this.anchorOffset, bounds.y + bounds.height / 2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export interface DefaultTaskGroupProps {
truncateLength?: number;
/** Space between the label and the group. Defaults to 17 */
labelOffset?: number;
/** Center the label on the edge, overrides the label offset, only applicable to expanded groups */
centerLabelOnEdge?: boolean;
/** The Icon class to show in the label, ignored when labelIcon is specified */
labelIconClass?: string;
/** The label icon component to show in the label, takes precedence over labelIconClass */
Expand Down
Loading

0 comments on commit d6479b5

Please sign in to comment.