Skip to content

Latest commit

 

History

History
462 lines (388 loc) · 10.5 KB

vue-tree-chart.md

File metadata and controls

462 lines (388 loc) · 10.5 KB

Node.js CI

Demo page

https://ssthouse.github.io/tree-chart/#/svgTree

Demo Gif

demo gif

Using Tech

Svg version

  • use D3 to calculate node & link positon
  • use Vue to handle dom element entring and leaving
  • use Vue slot to let user easily use with their own data

How to use?

Svg version

1. install npm module

install Vue2 version

npm install @ssthouse/vue-tree-chart

install Vue3 version

npm install @ssthouse/vue3-tree-chart

2. register vue-tree component

For Vue2

import VueTree from '@ssthouse/vue-tree-chart'
import Vue from 'vue'
Vue.component('vue-tree', VueTree)

For Vue3

import VueTree from "@ssthouse/vue3-tree-chart";
import "@ssthouse/vue3-tree-chart/dist/vue3-tree-chart.css";

you can also check this codesanbox example

3. use component

3.1 basic usage

See Code
<template>
  <div class="container">
    <vue-tree
      style="width: 800px; height: 600px; border: 1px solid gray;"
      :dataset="sampleData"
      :config="treeConfig"
    >
    </vue-tree>
  </div>
</template>

<script>
export default {
  name: 'treemap',
  data() {
    return {
      sampleData: {
        value: '1',
        children: [
          { value: '2', children: [{ value: '4' }, { value: '5' }] },
          { value: '3' }
        ]
      },
      treeConfig: { nodeWidth: 120, nodeHeight: 80, levelHeight: 200 }
    }
  }
}
</script>

<style scoped lang="less">
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
}
</style>

3.2 show collapsed node in different style

See Code
<template>
  <div class="container">
    <vue-tree
      style="width: 800px; height: 600px; border: 1px solid gray;"
      :dataset="sampleData"
      :config="treeConfig"
    >
      <template v-slot:node="{ node, collapsed }">
        <span
          class="tree-node"
          :style="{ border: collapsed ? '2px solid grey' : '' }"
          >{{ node.value }}</span
        >
      </template>
    </vue-tree>
  </div>
</template>

<script>
export default {
  name: 'treemap',
  data() {
    return {
      sampleData: {
        value: '1',
        children: [
          { value: '2', children: [{ value: '4' }, { value: '5' }] },
          { value: '3' }
        ]
      },
      treeConfig: { nodeWidth: 120, nodeHeight: 80, levelHeight: 200 }
    }
  }
}
</script>

<style scoped lang="less">
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tree-node {
  display: inline-block;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background-color: antiquewhite;
  text-align: center;
  line-height: 28px;
}
</style>

3.3 render rich media data

See Code
<template>
  <div class="container">
    <vue-tree
      style="width: 1000px; height: 600px; border: 1px solid gray;"
      :dataset="richMediaData"
      :config="treeConfig"
    >
      <template v-slot:node="{ node, collapsed }">
        <div
          class="rich-media-node"
          :style="{ border: collapsed ? '2px solid grey' : '' }"
        >
          <img
            :src="node.avatar"
            style="width: 48px; height: 48px; border-raduis: 4px;"
          />
          <span style="padding: 4px 0; font-weight: bold;"
            >能力值{{ node.value }}</span
          >
        </div>
      </template>
    </vue-tree>
  </div>
</template>

<script>
export default {
  name: 'treemap',
  data() {
    return {
      richMediaData: {
        name: 'James',
        value: 800,
        avatar:
          'https://gravatar.com/avatar/db51fdaf64d942180b5200ca37d155a4?s=400&d=robohash&r=x',
        children: [
          {
            name: 'Bob',
            value: 400,
            avatar:
              'https://gravatar.com/avatar/16b3b886b837257757c5961513396a06?s=400&d=robohash&r=x',
            children: [
              {
                name: 'C1',
                value: 100,
                avatar:
                  'https://gravatar.com/avatar/4ee8775f23f12755db978cccdc1356d9?s=400&d=robohash&r=x'
              },
              {
                name: 'C2',
                value: 300,
                avatar:
                  'https://gravatar.com/avatar/d3efa8fa639bdada96a7d0b4372e0a96?s=400&d=robohash&r=x'
              },
              {
                name: 'C3',
                value: 200,
                avatar:
                  'https://gravatar.com/avatar/4905bc3e5dc51a61e3b490ccf1891107?s=400&d=robohash&r=x'
              }
            ]
          },
          {
            name: 'Smith',
            value: 200,
            avatar:
              'https://gravatar.com/avatar/d05d081dbbb513180025300b715d5656?s=400&d=robohash&r=x',
            children: [
              {
                name: 'S1',
                value: 230,
                avatar:
                  'https://gravatar.com/avatar/60c1e69e690d943c5dc06568148debc4?s=400&d=robohash&r=x'
              }
            ]
          },
          {
            name: 'Jackson',
            value: 300,
            avatar:
              'https://gravatar.com/avatar/581f7a711c815d9671c35ebd815ec1e4?s=400&d=robohash&r=x'
          }
        ]
      },
      treeConfig: { nodeWidth: 120, nodeHeight: 80, levelHeight: 200 }
    }
  }
}
</script>

<style scoped lang="less">
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.rich-media-node {
  width: 80px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  color: white;
  background-color: #f7c616;
  border-radius: 4px;
}
</style>

3.4 render tree with multiple parents

See Code
<template>
  <div class='container'>
    <vue-tree
      style="width: 800px; height: 600px; border: 1px solid gray;"
      :dataset="vehicules"
      :config="treeConfig"
      linkStyle="straight"
    >
      <template v-slot:node="{ node, collapsed }">
        <div
          class="rich-media-node"
          :style="{ border: collapsed ? '2px solid grey' : '' }"
        >
          <span style="padding: 4px 0; font-weight: bold;"
          >能力值{{ node.name }}</span
          >
        </div>
      </template>
    </vue-tree>
  </div>
</template>
<script>
export default {
  name: 'treemap',
  data() {
    return {
      vehicules: {
        name: 'Wheels',
        children: [
          {
            name: 'Wings',
            children: [
              {
                name: 'Plane'
              }
            ]
          },
          {
            name: 'Piston',
            customID: 3
          },
          {
            name: 'Carburetor',
            children: [
              {
                name: 'Truck',
                customID: 2
              },
              {
                name: 'Car',
                customID: 2
              }
            ]
          },
          {
            name: 'Valve',
            customID: 4
          },
          {
            name: 'Crankshaft',
            customID: 1
          }
        ],
        links: [
          { parent: 1, child: 2 },
          { parent: 3, child: 2 },
          { parent: 4, child: 2 }
        ],
        identifier: 'customID'
      },
      treeConfig: { nodeWidth: 120, nodeHeight: 80, levelHeight: 200 }
    }
  }
}
</script>

<style scoped lang="less">
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.rich-media-node {
  width: 80px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  color: white;
  background-color: #f7c616;
  border-radius: 4px;
}
</style>

4. API

4.1 props

type default description
dataset [Object,Array] null nested tree data or an array of nested tree (multi root tree)
config Object {
nodeWidth: 100,
nodeHeight: 100,
levelHeight: 200
}
nodeWidth and nodeHeight config the tree node size. levelHeight is tree row height
linkStyle String 'curve' control link style, options: 'curve' or 'straight'
direction string 'vertical' control tree chart direction, options: 'vertical' or 'horizontal'
collapse-enabled Boolean true Control whether when clicking on a node it collapses its children

4.2 slot

this component only support default slot.

a sample usage like this:

<template v-slot:node="{ node, collapsed }">
  <span
    class="tree-node"
    :style="{ border: collapsed ? '2px solid grey' : '' }"
    >{{ node.value }}</span
  >
</template>

there are two slot params provided to render slot content:

slot param type description
node Object current node data to be rendered
collapsed Boolean current node collapse status

4.3 API > zoom

use vue ref to call zoom api.

support methods:

zoom in: this.$refs.tree.zoomIn()

zoom out: this.$refs.tree.zoomOut()

restore initial scale: this.$refs.tree.restoreScale()

Build Setup

# install dependencies
npm install

# serve with hot reload at localhost
npm run dev

# build for production with minification (build to ./docs folder, which can be auto servered by github page 🤓)
npm run build