Post

3. custom node

ROS2에 대해 알아보자

3. custom node

Custom Node

  • 기본적으로 제공하는 노드형태(input/default/output) 외에 커스텀한 노드 형태 정의 가능(노드/핸들/엣지)

사용방법 (커스텀 타입/v-slot 생성 방법 2가지가 있음)

커스텀 타입으로 노드 생성

  • 커스텀 컴포넌트들을 생성 후 VueFlow 컴포넌트에 node-types 프롭스로 커스텀 노드 생성 가능 (커스텀 타입에 정의된 컴포넌트 렌더링을 수행)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
## FlowCanvas.vue
## script
import VariableNode from './customnodes/VariableNode.vue'
const customNodeTypes: CustomNode = {
  [CustomTypesDefine.VARIABLE_NODE]: markRaw(VariableNode),
}

## template
  <div class="d-flex flex-column">
    <div class="dnd-flow" @drop="onDrop">
      <VueFlow
        v-model:nodes="nodes"
        v-model:edges="edges"
        :node-types="customNodeTypes"
        @dragover="onDragOver"
        @dragleave="onDragLeave"
        @connect="onConnect"
      >
      ...
      </VueFlow>
      <FlowSidebar />
    </div>
  </div>

# Varible Node
<script lang="ts" setup>
import { Handle, Position } from '@vue-flow/core'
import { ref, watch } from 'vue'

const props = defineProps({
  data: Object,
})

const emit = defineEmits(['update:data'])
const value = ref('')

watch(value, (newValue) => {
  emit('update:data', { ...props.data, value: newValue })
})
</script>

<template>
  <div class="input-node font-style">
    <div class="d-flex flex-row justify-content-center">
      <h1>Number</h1>
      <input class="input-box" type="number" v-model="value" placeholder="Enter value" />
    </div>
    <Handle type="source" :position="Position.Bottom" />
  </div>
</template>

템플릿(v-slot)으로 노드 생성

  • 커스텀 컴포넌트들을 생성 후 VueFlow 내 template으로 생성
  • scoped slot을 통해 자식 컴포넌트에서 올려주는 프롭스와 템플릿 값들로 노드를 생성 (ex. 노드 외에도 줌 패널/ 커넥션 라인 등 scoped slot으로 커스터마이즈 가능)

    vue slot = > 부모가 원하는 콘텐츠를 삽입할 수 있지만, 자식의 데이터를 활용할 수 없음 scoped slot => 자식이 가진 데이터를 부모에게 전달할 수 있어서, 부모가 더 유연하게 렌더링할 수 있음. 동적 리스트, 재사용 가능한 UI 컴포넌트등 유연한 디자인이 필요할때 사용

  • ref. https://vuejs.org/guide/components/slots
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# App.vue

<script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { initialEdges, initialNodes } from './initial-elements.js'
import ValueNode from './ValueNode.vue'
import OperatorNode from './OperatorNode.vue'
import ResultNode from './ResultNode.vue'

const nodes = ref(initialNodes)

const edges = ref(initialEdges)
</script>

<template>
  <VueFlow class="math-flow" :nodes="nodes" :edges="edges" fit-view-on-init>
    <template #node-value="props">   ===> 자식 컴포넌트의 템플릿( ValueNode.vue) 받아와 렌더링을 수행하며, scoped slot 형태로 slot props를 받아와 랜더링 수행
      <ValueNode :id="props.id" :data="props.data" />
    </template>

    <template #node-operator="props">
      <OperatorNode :id="props.id" :data="props.data" />
    </template>

    <template #node-result="props">
      <ResultNode :id="props.id" />
    </template>

    <Background />

  </VueFlow>
</template>

# ValueNode.vue (id는 노드 생성  vue-flow에서 id 값을 관리하여 내려줌)

<script setup>
import { computed } from 'vue'
import { Handle, Position, useVueFlow } from '@vue-flow/core'

const props = defineProps(['id', 'data'])

const { updateNodeData } = useVueFlow()

const value = computed({
  get: () => props.data.value,
  set: (value) => updateNodeData(props.id, { value }),
})
</script>

<template>
  <input :id="`${id}-input`" v-model="value" type="number" class="nodrag" />

  <Handle type="source" :position="Position.Right" :connectable="false" />
</template>

Ref. https://vuejs.org/guide/components/slots#slot-content-and-outlet

This post is licensed under CC BY 4.0 by the author.