Skip to content

Commit

Permalink
Make nodes resizable
Browse files Browse the repository at this point in the history
  • Loading branch information
newcat committed Jan 2, 2024
1 parent 1bfb814 commit 0432e69
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 54 deletions.
27 changes: 1 addition & 26 deletions docs/visual-editor/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,29 +71,4 @@ const baklava = useBaklava();
baklava.settings.displayValueOnHover = true;
```

Available settings are:

```ts
interface IViewSettings {
/** Use straight connections instead of bezier curves */
useStraightConnections: boolean;
/** Show a minimap */
enableMinimap: boolean;
/** Background settings */
background: {
gridSize: number;
gridDivision: number;
subGridVisibleThreshold: number;
};
/** Sidebar settings */
sidebar: {
/** Width of the sidebar in pixels */
width: number;
/** Whether users should be able to resize the sidebar */
resizable: boolean;
};
/** Show interface value on port hover */
displayValueOnHover: boolean;
}
```

You can find all available settings <ApiLink type="interfaces" module="@baklavajs/renderer-vue" name="IViewSettings">here</ApiLink>.
1 change: 1 addition & 0 deletions packages/renderer-vue/playground/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const editor = baklavaView.editor;
baklavaView.settings.enableMinimap = true;
baklavaView.settings.sidebar.resizable = false;
baklavaView.settings.displayValueOnHover = true;
baklavaView.settings.nodes.resizable = true;
const engine = new DependencyEngine(editor);
engine.events.afterRun.subscribe(token, (r) => {
engine.pause();
Expand Down
3 changes: 2 additions & 1 deletion packages/renderer-vue/src/components/Minimap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,9 @@ watch([showViewBounds, graph.value.panning, () => graph.value.scaling, () => gra
});
const nodePositions = computed(() => graph.value.nodes.map((n) => n.position));
const nodeSizes = computed(() => graph.value.nodes.map((n) => n.width));
watch(
nodePositions,
[nodePositions, nodeSizes],
() => {
updateCanvas();
},
Expand Down
6 changes: 4 additions & 2 deletions packages/renderer-vue/src/graph/createSubgraph.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import {
import { v4 as uuidv4 } from "uuid";
import { reactive, Ref } from "vue";
import type { ICommand, ICommandHandler } from "../commands";
import { useViewModel } from "../utility";
import { IViewNodeState } from "../node/viewNode";
import { SaveSubgraphCommand, SAVE_SUBGRAPH_COMMAND } from "./saveSubgraph.command";
import type { SwitchGraph } from "./switchGraph";
import { SubgraphInputNode, SubgraphOutputNode } from "./subgraphInterfaceNodes";
import { IViewNodeState } from "../node/viewNode";

export const CREATE_SUBGRAPH_COMMAND = "CREATE_SUBGRAPH";
export type CreateSubgraphCommand = ICommand<void>;
Expand All @@ -31,6 +32,7 @@ export function registerCreateSubgraphCommand(
};

const createSubgraph = () => {
const { viewModel } = useViewModel();
const graph = displayedGraph.value;
const editor = displayedGraph.value.editor;

Expand Down Expand Up @@ -68,7 +70,7 @@ export function registerCreateSubgraphCommand(
inputNode.inputs.name.value = conn.to.name;
nodeStates.push({
...inputNode.save(),
position: { x: xRight - 300, y: yTop + idx * 200 },
position: { x: xRight - viewModel.value.settings.nodes.defaultWidth - 100, y: yTop + idx * 200 },
} as Omit<IViewNodeState, "twoColumn" | "width">);
connectionStates.push({ id: uuidv4(), from: inputNode.outputs.placeholder.id, to: conn.to.id });
interfaceIdMap.set(conn.to.id, inputNode.graphInterfaceId);
Expand Down
40 changes: 35 additions & 5 deletions packages/renderer-vue/src/node/Node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
:data-node-type="node.type"
@pointerdown="select"
>
<div v-if="viewModel.settings.nodes.resizable" class="__resize-handle" @mousedown="startResize" />

<slot name="title">
<div class="__title" @pointerdown.self.stop="startDrag">
<template v-if="!renaming">
Expand Down Expand Up @@ -63,7 +65,7 @@
</template>

<script setup lang="ts">
import { ref, computed, nextTick, onUpdated, onMounted } from "vue";
import { ref, computed, nextTick, onUpdated, onMounted, onBeforeUnmount } from "vue";
import { AbstractNode, GRAPH_NODE_TYPE_PREFIX, IGraphNode } from "@baklavajs/core";
import { useGraph, useViewModel } from "../utility";
Expand Down Expand Up @@ -92,6 +94,7 @@ const el = ref<HTMLElement | null>(null);
const renaming = ref(false);
const tempName = ref("");
const renameInputEl = ref<HTMLInputElement | null>(null);
const isResizing = ref(false);
const showContextMenu = ref(false);
const contextMenuItems = computed(() => {
Expand All @@ -114,9 +117,9 @@ const classes = computed(() => ({
}));
const styles = computed(() => ({
top: `${props.node.position?.y ?? 0}px`,
left: `${props.node.position?.x ?? 0}px`,
width: `${props.node.width ?? 200}px`,
"top": `${props.node.position?.y ?? 0}px`,
"left": `${props.node.position?.x ?? 0}px`,
"--width": `${props.node.width ?? viewModel.value.settings.nodes.defaultWidth}px`,
}));
const displayedInputs = computed(() => Object.values(props.node.inputs).filter((ni) => !ni.hidden));
Expand Down Expand Up @@ -166,6 +169,33 @@ const onRender = () => {
}
};
onMounted(onRender);
const startResize = (ev: MouseEvent) => {
isResizing.value = true;
ev.preventDefault();
};
const doResize = (ev: MouseEvent) => {
if (!isResizing.value) return;
const newWidth = props.node.width + ev.movementX / graph.value.scaling;
const minWidth = viewModel.value.settings.nodes.minWidth;
const maxWidth = viewModel.value.settings.nodes.maxWidth;
props.node.width = Math.max(minWidth, Math.min(maxWidth, newWidth));
};
const stopResize = () => {
isResizing.value = false;
};
onMounted(() => {
onRender();
window.addEventListener("mousemove", doResize);
window.addEventListener("mouseup", stopResize);
});
onUpdated(onRender);
onBeforeUnmount(() => {
window.removeEventListener("mousemove", doResize);
window.removeEventListener("mouseup", stopResize);
});
</script>
8 changes: 6 additions & 2 deletions packages/renderer-vue/src/node/viewNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ export interface IViewNodeState extends INodeState<unknown, unknown> {
twoColumn: boolean;
}

export function setViewNodeProperties(node: AbstractNode) {
export interface SetViewNodePropertiesSettings {
defaultWidth: number;
}

export function setViewNodeProperties(node: AbstractNode, settings: SetViewNodePropertiesSettings) {
node.position = node.position ?? { x: 0, y: 0 };
node.disablePointerEvents = false;
node.twoColumn = node.twoColumn ?? false;
node.width = node.width ?? 200;
node.width = node.width ?? settings.defaultWidth;
}
53 changes: 37 additions & 16 deletions packages/renderer-vue/src/viewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,40 @@ export interface IViewSettings {
};
/** Show interface value on port hover */
displayValueOnHover: boolean;
/** Node settings */
nodes: {
/** Minimum width of a node */
minWidth: number;
/** Maximum width of a node */
maxWidth: number;
/** Default width of a node */
defaultWidth: number;
/** Whether users should be able to resize nodes */
resizable: boolean;
};
}

const DEFAULT_SETTINGS: () => IViewSettings = () => ({
useStraightConnections: false,
enableMinimap: false,
background: {
gridSize: 100,
gridDivision: 5,
subGridVisibleThreshold: 0.6,
},
sidebar: {
width: 300,
resizable: true,
},
displayValueOnHover: false,
nodes: {
defaultWidth: 200,
maxWidth: 320,
minWidth: 150,
resizable: false,
},
});

export interface IBaklavaViewModel extends IBaklavaTapable {
editor: Editor;
/** Currently displayed graph */
Expand Down Expand Up @@ -62,20 +94,7 @@ export function useBaklava(existingEditor?: Editor): IBaklavaViewModel {

const isSubgraph = computed(() => displayedGraph.value && displayedGraph.value !== editor.value.graph);

const settings: IViewSettings = reactive({
useStraightConnections: false,
enableMinimap: false,
background: {
gridSize: 100,
gridDivision: 5,
subGridVisibleThreshold: 0.6,
},
sidebar: {
width: 300,
resizable: true,
},
displayValueOnHover: false,
} satisfies IViewSettings);
const settings: IViewSettings = reactive(DEFAULT_SETTINGS());

const commandHandler = useCommandHandler();
const history = useHistory(displayedGraph, commandHandler);
Expand Down Expand Up @@ -107,7 +126,7 @@ export function useBaklava(existingEditor?: Editor): IBaklavaViewModel {
if (newValue) {
newValue.nodeHooks.beforeLoad.subscribe(token, (state, node) => {
node.position = (state as IViewNodeState).position ?? { x: 0, y: 0 };
node.width = (state as IViewNodeState).width ?? 200;
node.width = (state as IViewNodeState).width ?? settings.nodes.defaultWidth;
node.twoColumn = (state as IViewNodeState).twoColumn ?? false;
return state;
});
Expand Down Expand Up @@ -138,7 +157,9 @@ export function useBaklava(existingEditor?: Editor): IBaklavaViewModel {
return state;
});

newValue.graphEvents.beforeAddNode.subscribe(token, (node) => setViewNodeProperties(node));
newValue.graphEvents.beforeAddNode.subscribe(token, (node) =>
setViewNodeProperties(node, { defaultWidth: settings.nodes.defaultWidth }),
);

editor.value.registerNodeType(SubgraphInputNode, { category: "Subgraphs" });
editor.value.registerNodeType(SubgraphOutputNode, { category: "Subgraphs" });
Expand Down
48 changes: 46 additions & 2 deletions packages/themes/src/classic/components/node.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
.baklava-node {
max-width: 20rem;
background: var(--baklava-node-color-background);
color: var(--baklava-node-color-foreground);
border: 1px solid transparent;
border-radius: var(--baklava-node-border-radius);
position: absolute;
box-shadow: 0 0 4px #000000cc;
transition: border-color var(--baklava-visual-transition), box-shadow var(--baklava-visual-transition);
transition:
border-color var(--baklava-visual-transition),
box-shadow var(--baklava-visual-transition);

width: var(--width);

&:hover {
border-color: var(--baklava-node-color-hover);

& .__resize-handle::after {
opacity: 1;
}
}

&.--selected {
Expand Down Expand Up @@ -76,4 +83,41 @@
grid-column: 2;
}
}

& .__resize-handle {
position: absolute;
right: 0;
bottom: 0;
width: 1rem;
height: 1rem;
transform: translateX(50%);
cursor: ew-resize;

&::after {
content: "";
position: absolute;
bottom: 0;
left: -0.5rem;
width: 1rem;
height: 1rem;
opacity: 0;
border-bottom-right-radius: var(--baklava-node-border-radius);
transition: opacity var(--baklava-visual-transition);
background: linear-gradient(
-45deg,
transparent 10%,
var(--baklava-node-color-resize-handle) 10%,
var(--baklava-node-color-resize-handle) 15%,
transparent 15%,
transparent 30%,
var(--baklava-node-color-resize-handle) 30%,
var(--baklava-node-color-resize-handle) 35%,
transparent 35%,
transparent 50%,
var(--baklava-node-color-resize-handle) 50%,
var(--baklava-node-color-resize-handle) 55%,
transparent 55%
);
}
}
}
1 change: 1 addition & 0 deletions packages/themes/src/classic/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
--baklava-node-color-foreground: white;
--baklava-node-color-hover: #5379b577;
--baklava-node-color-selected: var(--baklava-control-color-primary);
--baklava-node-color-resize-handle: var(--baklava-control-color-background);
--baklava-node-title-color-background: black;
--baklava-node-title-color-foreground: white;
--baklava-group-node-title-color-background: rgb(5, 75, 5);
Expand Down
1 change: 1 addition & 0 deletions packages/themes/src/syrup-dark/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
--baklava-node-color-foreground: white;
--baklava-node-color-hover: #e28c4677;
--baklava-node-color-selected: var(--baklava-control-color-primary);
--baklava-node-color-resize-handle: var(--baklava-control-color-background);
--baklava-node-title-color-background: #151a24;
--baklava-node-title-color-foreground: white;
--baklava-group-node-title-color-background: #215636;
Expand Down

0 comments on commit 0432e69

Please sign in to comment.