# Custom rendering

# Node rendering

<template>
  <div class="container">
    <input
      class="scale-handler"
      type="range"
      :min="0.1"
      :max="2"
      :step="0.01"
      v-model="scaleRatio"
    />
    <vis-tree
      class="vis-tree"
      ref="visTree"
      :data-source="dataSource"
      :scale-ratio="scaleRatio"
      :options="options"
    >
      <template v-slot:node="nodeSlotProps">
        <div class="node-container">
          <div class="node-content">
            {{nodeSlotProps.node.key}}
          </div>

          <i
            v-if="nodeSlotProps.node.children && nodeSlotProps.node.children.length > 0"
            class="node-switcher"
            :class="nodeSlotProps.expanded ? 'el-icon-circle-plus-outline' : 'el-icon-remove-outline'"
            :style="{ color: `${nodeSlotProps.expanded ? 'green' : 'red'}` }"
            @click="() => toggleNodeExpanded(nodeSlotProps.node.key)"
          />
        </div>
      </template>
    </vis-tree>
  </div>
</template>

<script>
import VisTree from '@vis-tree/vue';
import 'element-plus/lib/theme-chalk/index.css';

const originDataSource = {
  key: 'O',
  children: [
    {
      key: 'E',
      children: [
        {
          key: 'A',
        },
        {
          key: 'D',
          children: [
            {
              key: 'B',
            },
            {
              key: 'C',
            },
          ],
        },
      ],
    },
    {
      key: 'F',
    },
    {
      key: 'N',
      children: [
        {
          key: 'G',
        },
        {
          key: 'M',
          children: [
            {
              key: 'H',
            },
            {
              key: 'I',
            },
            {
              key: 'J',
            },
            {
              key: 'K',
            },
            {
              key: 'L',
            },
          ],
        },
      ],
    },
  ],
};

export default {
  props: {
    msg: String,
  },
  components: {
    VisTree,
  },
  data() {
    return {
      scaleRatio: 1,
      dataSource: originDataSource,
      options: {
          defaultScrollInfo: {
            key: originDataSource.key,
            top: 40,
          },
          defaultExpandAll: true,
      }
    };
  },
  methods: {
    toggleNodeExpanded(key) {
      this.$refs.visTree.toggleNodeExpanded(key);
    },
  }
};
</script>

<style scoped>
.container {
  position: relative;
  background-color: #fff;
  border: 1px solid #ebedf1;
  border-radius: 1px;
}
.scale-handler {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 1;
}
.vis-tree {
  width: 100%;
  height: 400px;
}
.node-container {
  height: 100%;
  box-sizing: border-box;
  background: #fff;
  border: 1px solid black;
}
.node-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.node-switcher {
  width: 14px;
  height: 14px;
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, -50%);
  cursor: pointer;
  background: #fff;
}
</style>
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

The rendering of the node is achieved by <template v-slot:node="nodeSlotProps"></template>nodeSlotProps is an object,which has the following properties:

  • node: Current node
  • expanded: true means the node is in the expanded state, false means the node is in the collapsed state. If the node has no children, then it must be false
  • parentNode: The parent node of the current node. For the root node, this attribute is undefined

The DOM structure is as follows:

<template>
  <!-- Its width and height are determined by options.nodeWidth and options.nodeHeight respectively -->
  <div class="tree-node-wrapper">
    <div class="tree-node-content">
      <slot name="node"></slot>
    </div>
  </div>
</template>

<style>
.tree-node-wrapper {
  position: absolute;
  cursor: auto;
}

.tree-node-content {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 1;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Rendering of connecting lines

<template>
  <div class="container">
    <input
      class="scale-handler"
      type="range"
      :min="0.1"
      :max="2"
      :step="0.01"
      v-model="scaleRatio"
    />
    <vis-tree
      class="vis-tree"
      ref="visTree"
      :data-source="dataSource"
      :scale-ratio="scaleRatio"
      :options="options"
    >
      <template v-slot:node="nodeSlotProps">
        <div class="node-container">
          <div class="node-content">
            {{ nodeSlotProps.node.key }}
          </div>

          <i
            v-if="
              nodeSlotProps.node.children &&
              nodeSlotProps.node.children.length > 0
            "
            class="node-switcher"
            :class="
              nodeSlotProps.expanded
                ? 'el-icon-circle-plus-outline'
                : 'el-icon-remove-outline'
            "
            :style="{ color: `${nodeSlotProps.expanded ? 'green' : 'red'}` }"
            @click="() => toggleNodeExpanded(nodeSlotProps.node.key)"
          />
        </div>
      </template>

      <template v-slot:line="lineSlotProps">
        <div
          v-if="lineSlotProps.containerWidth === 0"
          :style="{
            width: '1px',
            height: `${lineSlotProps.containerHeight}px`,
            background: 'black',
          }"
        />

        <div
          v-if="lineSlotProps.containerHeight === 0"
          :style="{
            width: `${lineSlotProps.containerWidth}px`,
            height: '1px',
            background: 'black',
          }"
        />

        <svg
          v-if="lineSlotProps.containerWidth && lineSlotProps.containerHeight"
          :width="`${lineSlotProps.containerWidth}px`"
          :height="`${lineSlotProps.containerHeight}px`"
        >
          <path
            :d="`M ${lineSlotProps.startPointCoordinate[0]} ${lineSlotProps.startPointCoordinate[1]}, L ${lineSlotProps.stopPointCoordinate[0]} ${lineSlotProps.stopPointCoordinate[1]}`"
            strokeWidth="1px"
            fill="none"
            stroke="black"
          />
        </svg>
      </template>
    </vis-tree>
  </div>
</template>

<script>
import VisTree from "@vis-tree/vue";
import "element-plus/lib/theme-chalk/index.css";

const originDataSource = {
  key: "O",
  children: [
    {
      key: "E",
      children: [
        {
          key: "A",
        },
        {
          key: "D",
          children: [
            {
              key: "B",
            },
            {
              key: "C",
            },
          ],
        },
      ],
    },
    {
      key: "F",
    },
    {
      key: "N",
      children: [
        {
          key: "G",
        },
        {
          key: "M",
          children: [
            {
              key: "H",
            },
            {
              key: "I",
            },
            {
              key: "J",
            },
            {
              key: "K",
            },
            {
              key: "L",
            },
          ],
        },
      ],
    },
  ],
};

export default {
  props: {
    msg: String,
  },
  components: {
    VisTree,
  },
  data() {
    return {
      scaleRatio: 1,
      dataSource: originDataSource,
      options: {
        defaultScrollInfo: {
          key: originDataSource.key,
          top: 40,
        },
        defaultExpandAll: true,
          lineType: "none",
      },
    };
  },
  methods: {
    toggleNodeExpanded(key) {
      this.$refs.visTree.toggleNodeExpanded(key);
    },
  },
};
</script>

<style scoped>
.container {
  position: relative;
  background-color: #fff;
  border: 1px solid #ebedf1;
  border-radius: 1px;
}
.scale-handler {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 1;
}
.vis-tree {
  width: 100%;
  height: 400px;
}
.node-container {
  height: 100%;
  box-sizing: border-box;
  background: #fff;
  border: 1px solid black;
}
.node-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.node-switcher {
  width: 14px;
  height: 14px;
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, -50%);
  cursor: pointer;
  background: #fff;
}
</style>
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

The rendering of the line is achieved by <template v-slot:line="lineSlotProps"></template>lineSlotProps is an object,which has the following properties:

  • startNode: Start node of the connecting line
  • stopNode: End node of the connecting line
  • containerWidth: The width of the rectangle with the connecting line as the diagonal
  • containerHeight: The height of the rectangle with the connecting line as the diagonal
  • startPointCoordinate: In the coordinate system formed by the rectangle with the connecting line as the diagonal, the coordinates of the starting point
  • stopPointCoordinate: In the coordinate system formed by the rectangle with the connecting line as the diagonal, the coordinates of the end point

The DOM structure is as follows:

<template>
  <!-- Its width and height are containerWidth and containerHeight respectively -->
  <div class="tree-custom-line">
    <slot name="line"></slot>
  </div>
</template>

<style>
.tree-custom-line {
  position: absolute;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
Last Updated: 5/9/2021, 9:20:47 AM