Showing preview only (1,770K chars total). Download the full file or copy to clipboard to get everything.
Repository: ssthouse/vue-tree-chart
Branch: master
Commit: dc9b357fc50d
Files: 99
Total size: 1.7 MB
Directory structure:
gitextract_r67z_mc_/
├── .github/
│ └── workflows/
│ ├── build.yml
│ ├── deploy.yml
│ └── release.yml
├── .gitignore
├── .npmrc
├── LICENSE.md
├── README-CN.md
├── README.md
├── docs/
│ ├── canvas-tree-chart-CN.md
│ ├── canvas-tree-chart.md
│ ├── react-tree-chart.md
│ ├── tech-underneath.md
│ ├── vue-tree-chart-CN.md
│ └── vue-tree-chart.md
├── lerna.json
├── package.json
├── packages/
│ ├── react-tree-chart/
│ │ ├── .babelrc
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── public/
│ │ │ ├── index.html
│ │ │ ├── manifest.json
│ │ │ └── robots.txt
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── demo/
│ │ │ │ ├── App.css
│ │ │ │ ├── App.tsx
│ │ │ │ ├── index.css
│ │ │ │ └── react-app-env.d.ts
│ │ │ ├── index.css
│ │ │ ├── index.tsx
│ │ │ ├── react-app-env.d.ts
│ │ │ ├── setupTests.ts
│ │ │ └── tree-chart/
│ │ │ ├── react-tree-chart.scss
│ │ │ ├── react-tree-chart.tsx
│ │ │ └── typings.d.ts
│ │ └── tsconfig.json
│ ├── tree-chart-core/
│ │ ├── .eslintrc.js
│ │ ├── .gitignore
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── base/
│ │ │ │ └── uuid.ts
│ │ │ ├── index.ts
│ │ │ └── tree-chart/
│ │ │ ├── constant.ts
│ │ │ ├── index.ts
│ │ │ ├── tree-chart.ts
│ │ │ └── util.ts
│ │ └── tsconfig.json
│ ├── tree-chart-demo/
│ │ ├── build/
│ │ │ ├── webpack.config.base.js
│ │ │ ├── webpack.config.dev.js
│ │ │ └── webpack.config.prod.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── base/
│ │ │ │ ├── color-util.ts
│ │ │ │ ├── data-generator.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── uuid.ts
│ │ │ ├── components/
│ │ │ │ ├── CanvasTree.vue
│ │ │ │ ├── VueTreeDemo.vue
│ │ │ │ └── org-chart.ts
│ │ │ ├── demo/
│ │ │ │ ├── App.vue
│ │ │ │ ├── google-icon.css
│ │ │ │ ├── main.ts
│ │ │ │ └── router/
│ │ │ │ ├── constant.ts
│ │ │ │ └── index.ts
│ │ │ └── vue.shims.d.ts
│ │ ├── template/
│ │ │ └── index.html
│ │ └── tsconfig.json
│ ├── vue-tree-chart/
│ │ ├── .babelrc
│ │ ├── .editorconfig
│ │ ├── .eslintignore
│ │ ├── .eslintrc.js
│ │ ├── .postcssrc.js
│ │ ├── .prettierignore
│ │ ├── README.md
│ │ ├── build/
│ │ │ ├── webpack.config.base.js
│ │ │ ├── webpack.config.dev.js
│ │ │ └── webpack.config.library.js
│ │ ├── library/
│ │ │ ├── .gitkeep
│ │ │ └── vue-tree-chart.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── base/
│ │ │ │ └── uuid.ts
│ │ │ ├── demo/
│ │ │ │ ├── App.vue
│ │ │ │ └── main.ts
│ │ │ ├── vue-tree/
│ │ │ │ ├── VueTree.vue
│ │ │ │ └── index.ts
│ │ │ └── vue.shims.d.ts
│ │ ├── template/
│ │ │ └── index.html
│ │ └── tsconfig.json
│ └── vue3-tree-chart/
│ ├── .gitignore
│ ├── README.md
│ ├── babel.config.js
│ ├── package.json
│ ├── public/
│ │ └── index.html
│ ├── src/
│ │ ├── App.vue
│ │ ├── base/
│ │ │ └── uuid.js
│ │ ├── components/
│ │ │ └── HelloWorld.vue
│ │ ├── main.js
│ │ └── vue-tree/
│ │ ├── VueTree.vue
│ │ └── index.js
│ └── vite.config.js
└── scripts/
└── publish-safe.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/build.yml
================================================
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Check Build
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: install dependencies
run: |
npm install
./node_modules/.bin/lerna bootstrap
- name: (tree-chart-core)Build
working-directory: packages/tree-chart-core
run: npm run build
- name: (vue-tree-chart)Build
working-directory: packages/vue-tree-chart
run: npm run build:component
- name: (tree-chart-demo)Build
working-directory: packages/tree-chart-demo
run: npm run build
================================================
FILE: .github/workflows/deploy.yml
================================================
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Deploy Github Page
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: install dependencies
run: |
npm install
./node_modules/.bin/lerna bootstrap
- name: Build
working-directory: packages/tree-chart-demo
run: |
npm run build
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@releases/v3
with:
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: packages/tree-chart-demo/dist # The folder the action should deploy.
================================================
FILE: .github/workflows/release.yml
================================================
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Release
on:
push:
tags:
- "*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18.x"
registry-url: "https://registry.npmjs.org"
- name: install dependencies
run: |
npm install
./node_modules/.bin/lerna bootstrap
- run: npm run build:component
working-directory: packages/vue-tree-chart
- run: npm publish
working-directory: packages/vue-tree-chart
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
================================================
FILE: .gitignore
================================================
.DS_Store
node_modules/
dist
npm-debug.log*
yarn-debug.log*
yarn-error.log*
built/ # Ignore out dir in tsconfig.json
es
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
================================================
FILE: .npmrc
================================================
legacy-peer-deps=true
================================================
FILE: LICENSE.md
================================================
MIT License
Copyright (c) 2021 Shen Shuntian
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README-CN.md
================================================
## [English](./README.md) | [中文](./README-CN.md)
## Demo 页面
https://ssthouse.github.io/tree-chart/#/svgTree
## Demo 动图

## Vue Tree Chart (同时支持 Vue2 和 Vue3)
请参考: [vue-tree-chart](./docs/vue-tree-chart.md)
## Canvas Tree Chart
请参考: [canvas tree chart](./docs/canvas-tree-chart.md)
## 开始开发
```bash
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
```
================================================
FILE: README.md
================================================
## [English](./README.md) | [中文](./README-CN.md)
## Demo
https://ssthouse.github.io/tree-chart/#/svgTree
## Demo Gif

## Vue Tree Chart (support both Vue2 and Vue3)
please refer [vue-tree-chart](./docs/vue-tree-chart.md)
## React Tree Chart
please refer [react-tree-chart](./docs/react-tree-chart.md)
## Canvas Tree Chart
please refer [canvas tree chart](./docs/canvas-tree-chart.md)
## Build Setup
```bash
# 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
```
================================================
FILE: docs/canvas-tree-chart-CN.md
================================================
# Canvas Tree Chart
## Canvas 版本 使用到的技术点
- 将 D3.js 和 Canvas 一起使用,提升绘制效率(其中 D3.js 使用虚拟 DOM 就行渲染,Canvas 取虚拟 DOM 节点坐标进行绘制)
- 使用 `唯一颜色值`的方案,实现 Canvas 上点击事件的监听 (你也可以参考这篇文档了解其详细实现: https://medium.com/@lverspohl/how-to-turn-d3-and-canvas-into-good-friends-b7a240a32915)
## Canavs API
canvas 的版本, 因为其绘制过程较难抽象, 且仅仅在数据量较大的情况下才有意义,所以没有发布为 npm module.
如果你希望使用 canvas 版本的 tree-chart,可以将源代码下载下来,并进行一下步骤替换为自己的数据集:
- 将 `packages/tree-chart-demo/src/base/data-generator.js`文件中的数据替换为你自己的数据.
- 在 `packages/tree-chart-demo/src/components/org-chart.js`文件中,修改`drawShowCanvas`函数的绘制逻辑.
================================================
FILE: docs/canvas-tree-chart.md
================================================
# Canvas Tree Chart
## Canvas version Using Tech
- use D3.js with Canvas to draw organizationChart more efficiently.
- Use `unique-color` manner to identify mouse click event in Canvas (you can refer to https://medium.com/@lverspohl/how-to-turn-d3-and-canvas-into-good-friends-b7a240a32915 to see detail)
### Canvas version API
the canvas version is not published with npm module.
if you want to use this project's canvas version, please download the source code and edit with the following steps:
- replace the data in `packages/tree-chart-demo/src/base/data-generator.js` with your own nested data.
- add your data drawing logic in `packages/tree-chart-demo/src/components/org-chart.js #drawShowCanvas`
================================================
FILE: docs/react-tree-chart.md
================================================
## Demo page
https://codesandbox.io/s/react-tree-chart-544i2?file=/src/App.tsx
## How to use?
#### 1. install npm module
install **Vue2 version**
```shell
npm install @ssthouse/react-tree-chart
```
#### 2. import component
```javascript
import TreeChart from "@ssthouse/react-tree-chart";
import "@ssthouse/react-tree-chart/lib/react-tree-chart.css";
```
you can also check this [codesanbox example](https://codesandbox.io/s/react-tree-chart-544i2?file=/src/App.tsx)
#### 3. use component
================================================
FILE: docs/tech-underneath.md
================================================
## 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
================================================
FILE: docs/vue-tree-chart-CN.md
================================================
## [English](./vue-tree-chart.md)
## Demo 页面
https://ssthouse.github.io/tree-chart/#/svgTree
## Demo 动图

## 使用到的技术点
### Svg 版本
- 使用 D3.js 计算**节点**和**链接线**的坐标
- 使用 Vue 控制 DOM 节点的变更
- 使用 Vue slot 抽象节点渲染流程, 让使用者可以高度定制化节点绘制
### Canvas 版本
- 将 D3.js 和 Canvas 一起使用,提升绘制效率(其中 D3.js 使用虚拟 DOM 就行渲染,Canvas 取虚拟 DOM 节点坐标进行绘制)
- 使用 `唯一颜色值`的方案,实现 Canvas 上点击事件的监听 (你也可以参考这篇文档了解其详细实现: https://medium.com/@lverspohl/how-to-turn-d3-and-canvas-into-good-friends-b7a240a32915)
## 如何将图中数据替换为我的数据?
### Svg version
Svg 版本通过 Vue 进行了良好的封装,使用起来非常方便且灵活.
#### 1.安装
执行下面的命令安装 Svg 版本的 tree-chart
`npm install @ssthouse/vue-tree-chart`
#### 2. 注册 `vue-tree` 组件
```javascript
import VueTree from "@ssthouse/vue-tree-chart";
import Vue from "vue";
Vue.component("vue-tree", VueTree);
```
#### 3. 使用组件
**3.1 基本用法**
<details>
<summary>See Code</summary>
```vue
<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>
```
</details>

**3.2 使用 vue-slot 异化展示折叠节点**
<details>
<summary>See Code</summary>
```vue
<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>
```
</details>

**3.3 自定义渲染富媒体节点**
<details>
<summary>See Code</summary>
```vue
<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>
```
</details>

#### 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 | {<br />nodeWidth: 100,<br />nodeHeight: 100,<br />levelHeight: 200<br />} | nodeWidth 和 nodeHeight 用于配置树状图节点大小. levelHeight 用于配置树状图一层的高度 |
| linkStyle | String | 'curve' | 控制连接线样式, 可选项: 'curve' 或 'straight' |
| direction | string | 'vertical' | 控制树状图方向, 可选项: 'vertical' 或 'horizontal' |
**4.2 slot 参数**
该组件仅支持 **默认 slot**.
基本用法如下所示:
```vue
<template v-slot:node="{ node, collapsed }">
<span
class="tree-node"
:style="{ border: collapsed ? '2px solid grey' : '' }"
>{{ node.value }}</span
>
</template>
```
slot 提供两个参数用于渲染树状图节点内容。
| slot param | type | description |
| ---------- | ------- | -------------------------------- |
| node | Object | current node data to be rendered |
| collapsed | Boolean | current node collapse status |
**4.3 API > 缩放**
通过Vue ref,可以调用组件的缩放接口
支持的接口有:
缩小: `this.$refs.tree.zoomIn()`
放大: `this.$refs.tree.zoomOut()`
恢复原始大小: `this.$refs.tree.restoreScale()`
### Canavs 版本
canvas 的版本, 因为其绘制过程较难抽象, 且仅仅在数据量较大的情况下才有意义,所以没有发布为 npm module.
如果你希望使用 canvas 版本的 tree-chart,可以将源代码下载下来,并进行一下步骤替换为自己的数据集:
- 将 `/src/base/data-generator.js`文件中的数据替换为你自己的数据.
- 在 `/src/components/org-chart.js`文件中,修改`drawShowCanvas`函数的绘制逻辑.
## 开始开发
```bash
# 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
```
================================================
FILE: docs/vue-tree-chart.md
================================================
## [中文](./vue-tree-chart-CN.md)

## Demo page
https://ssthouse.github.io/tree-chart/#/svgTree
## 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**
```shell
npm install @ssthouse/vue-tree-chart
```
install **Vue3 version**
```shell
npm install @ssthouse/vue3-tree-chart
```
#### 2. register `vue-tree` component
For Vue2
```javascript
import VueTree from '@ssthouse/vue-tree-chart'
import Vue from 'vue'
Vue.component('vue-tree', VueTree)
```
For Vue3
```javascript
import VueTree from "@ssthouse/vue3-tree-chart";
import "@ssthouse/vue3-tree-chart/dist/vue3-tree-chart.css";
```
you can also check this [codesanbox example](https://codesandbox.io/s/vue3-tree-chart-demo-j11uj?file=/src/App.vue)
#### 3. use component
**3.1 basic usage**
<details>
<summary>See Code</summary>
```vue
<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>
```
</details>

**3.2 show collapsed node in different style**
<details>
<summary>See Code</summary>
```vue
<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>
```
</details>

**3.3 render rich media data**
<details>
<summary>See Code</summary>
```vue
<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>
```
</details>

**3.4 render tree with multiple parents**
<details>
<summary>See Code</summary>
```vue
<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>
```
</details>

#### 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 | {<br />nodeWidth: 100,<br />nodeHeight: 100,<br />levelHeight: 200<br />} | 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:
```vue
<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
```bash
# 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
```
================================================
FILE: lerna.json
================================================
{
"packages": [
"packages/*"
],
"version": "independent"
}
================================================
FILE: package.json
================================================
{
"name": "@ssthouse/vue-tree-chart",
"private": true,
"author": "ssthouse",
"scripts": {
"install:deps": "lerna bootstrap",
"build:component": "lerna run build:component --scope @ssthouse/vue-tree-chart",
"build:demo": "lerna run build --scope @ssthouse/vue-tree-chart",
"release:all": "lerna run release"
},
"devDependencies": {
"lerna": "^4.0.0"
}
}
================================================
FILE: packages/react-tree-chart/.babelrc
================================================
{
"presets": [
["@babel/preset-typescript", {
"allExtensions": true,
"isTsx": true
}],
"@babel/react"
]
}
================================================
FILE: packages/react-tree-chart/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
/lib
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
================================================
FILE: packages/react-tree-chart/README.md
================================================
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `yarn start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.\
You will also see any lint errors in the console.
### `yarn test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `yarn build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `yarn eject`
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
================================================
FILE: packages/react-tree-chart/package.json
================================================
{
"name": "@ssthouse/react-tree-chart",
"version": "0.2.0",
"dependencies": {
"@ssthouse/tree-chart-core": "^1.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-transition-group": "^1.2.1"
},
"main": "lib/react-tree-chart.js",
"module": "es/react-tree-chart.js",
"scripts": {
"start": "BROWSER=none react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build:component": "rm -rf lib es && rollup -c",
"release": "npm run build:component && ../../scripts/publish-safe.sh"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@babel/cli": "^7.16.0",
"@babel/preset-react": "^7.16.0",
"@babel/preset-typescript": "^7.16.0",
"@rollup/plugin-commonjs": "^21.0.1",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"react-scripts": "4.0.3",
"rollup": "^2.61.1",
"rollup-plugin-scss": "3",
"rollup-plugin-typescript2": "^0.31.1",
"sass": "^1.45.0",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
}
}
================================================
FILE: packages/react-tree-chart/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
================================================
FILE: packages/react-tree-chart/public/manifest.json
================================================
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
================================================
FILE: packages/react-tree-chart/public/robots.txt
================================================
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
================================================
FILE: packages/react-tree-chart/rollup.config.js
================================================
import commonjs from "@rollup/plugin-commonjs";
import typescript from "rollup-plugin-typescript2";
import scss from 'rollup-plugin-scss'
const packageJson = require("./package.json");
const rollupConfig = {
input: "./src/tree-chart/react-tree-chart.tsx",
output: [
{
file: packageJson.main,
format: "cjs",
sourcemap: true
},
{
file: packageJson.module,
format: "es",
sourcemap: true
}
],
plugins: [
typescript({
rollupCommonJSResolveHack: false,
clean: true,
}),
scss(),
// peerDepsExternal(),
// resolve(),
commonjs(),
]
};
export default rollupConfig;
================================================
FILE: packages/react-tree-chart/src/demo/App.css
================================================
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
================================================
FILE: packages/react-tree-chart/src/demo/App.tsx
================================================
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
================================================
FILE: packages/react-tree-chart/src/demo/index.css
================================================
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
================================================
FILE: packages/react-tree-chart/src/demo/react-app-env.d.ts
================================================
/// <reference types="react-scripts" />
================================================
FILE: packages/react-tree-chart/src/index.css
================================================
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
================================================
FILE: packages/react-tree-chart/src/index.tsx
================================================
import React, { useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import TreeChart from './tree-chart/react-tree-chart';
const sampleData = {
value: "1",
children: [
{ value: "2", children: [{ value: "4" }, { value: "5" }] },
{ value: "3" },
],
};
const sampleDataTwo = {
value: "100",
children: [
{ value: "3" },
{ value: "2", children: [{ value: "555" }, { value: "444" }] },
],
};
const Demo = () => {
const [dataSet, setDataset] = useState(sampleData);
const [enableCollapse, setEnableCollapse] = useState(true);
const treeChartRef = useRef<any>(null);
return <div>
<button onClick={() => setDataset(sampleDataTwo)}>change dataset</button>
<button onClick={() => {
console.log(!enableCollapse)
setEnableCollapse(!enableCollapse)
}}>toggle collapes enable</button>
<button onClick={() => treeChartRef.current.zoomIn()}>zoom in</button>
<button onClick={() => treeChartRef.current.zoomOut()}>zoom out</button>
<TreeChart
dataset={dataSet}
ref={treeChartRef}
collapseEnabled={enableCollapse}
style={{
width: '600px',
height: '600px',
border: '1px solid black'
}}
renderCustomNode={({ data, collapsed }) => <div>
<span style={{color: 'green'}}>{(data as any).value + (collapsed ? 'yes' : 'no')}</span>
</div>}
/>
</div>
}
ReactDOM.render(
<React.StrictMode>
<Demo />
</React.StrictMode>,
document.getElementById('root')
);
================================================
FILE: packages/react-tree-chart/src/react-app-env.d.ts
================================================
/// <reference types="react-scripts" />
================================================
FILE: packages/react-tree-chart/src/setupTests.ts
================================================
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
================================================
FILE: packages/react-tree-chart/src/tree-chart/react-tree-chart.scss
================================================
.tree-node-item-enter {
opacity: 0.01;
}
.tree-node-item-enter.tree-node-item-enter-active {
opacity: 1;
transition: opacity 800md ease-in-out;
}
.tree-node-item-leave {
opacity: 1;
}
.tree-node-item-leave.tree-node-item-leave-active {
opacity: 0.01;
transition: opacity 800ms ease-in-out;
}
.tree-container {
position: relative;
overflow: hidden;
.vue-tree {
position: relative;
}
> svg,
.dom-container {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
overflow: visible;
transform-origin: 0 50%;
}
.dom-container {
z-index: 1;
pointer-events: none;
}
}
.node-slot {
cursor: pointer;
pointer-events: all;
position: absolute;
background-color: transparent;
box-sizing: border-box;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
box-sizing: content-box;
transition: all 0.8s;
transition-timing-function: ease-in-out;
}
.tree-container {
.node {
fill: grey !important;
}
.link {
stroke-width: 2px !important;
fill: transparent !important;
stroke: #cecece !important;
}
}
================================================
FILE: packages/react-tree-chart/src/tree-chart/react-tree-chart.tsx
================================================
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import TreeChartCore, { DEFAULT_LEVEL_HEIGHT, DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH, Direction, TreeLinkStyle } from '@ssthouse/tree-chart-core';
import { CSSTransitionGroup } from 'react-transition-group'
import './react-tree-chart.scss';
const formatDimension = (dimension: number | string) => {
if (typeof dimension === "number") return `${dimension}px`;
if (dimension.indexOf("px") !== -1) {
return dimension;
} else {
return `${dimension}px`;
}
};
export interface TreeChartNodeProps {
data: unknown;
collapsed: boolean;
}
interface TreeChartConfig {
nodeWidth: number;
nodeHeight: number;
levelHeight: number;
}
interface TreeChartProps {
/** basic tree node size config */
config?: TreeChartConfig;
/** link node with straight line or curve line */
linkStyle?: TreeLinkStyle;
/** chart direction, vertical or horizontal */
direction?: Direction;
/** if chart node can be click to toggle collapse status */
collapseEnabled?: boolean;
dataset: Object | Object[];
/** css style for contaienr Div */
style?: React.CSSProperties;
/**
* custom tree node component
* default node is <span>{value}</span>
* */
renderCustomNode?: React.FC<TreeChartNodeProps>;
}
const DEFAULT_CONFIG = {
nodeWidth: DEFAULT_NODE_WIDTH,
nodeHeight: DEFAULT_NODE_HEIGHT,
levelHeight: DEFAULT_LEVEL_HEIGHT,
};
const TreeChart = forwardRef((props: TreeChartProps, ref) => {
const {
direction = Direction.VERTICAL,
config = DEFAULT_CONFIG,
dataset,
collapseEnabled = true,
style = {},
renderCustomNode: customNode
} = props;
const [treeChartCore, setTreeChartCore] = useState<TreeChartCore>();
const [initialTransformStyle, setInitialTransformStyle] = useState({})
const [nodeDataList, setNodeDataList] = useState<any[]>([]);
// refs
const containerRef = useRef<HTMLDivElement>(null);
const domContainerRef = useRef<HTMLDivElement>(null);
const svgRef = useRef<SVGSVGElement>(null);
// init tree chart core with refs
useEffect(() => {
console.log('update collapse', collapseEnabled)
const treeChartCore = new TreeChartCore({
svgElement: svgRef.current as SVGElement,
domElement: domContainerRef.current as HTMLDivElement,
treeContainer: containerRef.current as HTMLDivElement,
dataset,
collapseEnabled,
treeConfig: config,
direction,
});
setTreeChartCore(treeChartCore);
}, [collapseEnabled, dataset, config])
useEffect(() => {
if (!treeChartCore) return;
treeChartCore.init();
const nodeDataList = treeChartCore.getNodeDataList();
const initialTransformStyle = treeChartCore.getInitialTransformStyle();
setInitialTransformStyle(initialTransformStyle)
setNodeDataList(nodeDataList);
}, [treeChartCore]);
// update direction when it changes
useEffect(() => {
if (!treeChartCore) return;
treeChartCore.updateDirection(direction);
const nodeDataList = treeChartCore.getNodeDataList();
const initialTransformStyle = treeChartCore.getInitialTransformStyle();
setInitialTransformStyle(initialTransformStyle);
setNodeDataList(nodeDataList);
}, [direction, treeChartCore]);
const onClickNode = (index: number) => {
if (!treeChartCore) return;
treeChartCore.onClickNode(index);
setNodeDataList(treeChartCore.getNodeDataList());
}
useImperativeHandle(ref, () => {
return {
zoomIn() {
treeChartCore?.zoomIn();
},
zoomOut() {
treeChartCore?.zoomOut();
},
restoreScale() {
treeChartCore?.setScale(1);
},
}
})
return <div className="tree-container"
ref={containerRef} style={style}>
<svg className="svg vue-tree" ref={svgRef} style={initialTransformStyle}></svg>
<div
className="dom-container"
ref={domContainerRef}
style={initialTransformStyle}
>
<CSSTransitionGroup
transitionName="tree-node-item"
transitionEnterTimeout={800}
transitionLeaveTimeout={800}>
{
nodeDataList.map((node, index) => {
return <div
className="node-slot"
onClick={() => onClickNode(index)}
key={node.data._key}
style={{
left: formatDimension(
direction === Direction.VERTICAL ? node.x : node.y
),
top: formatDimension(
direction === Direction.VERTICAL ? node.y : node.x
),
width: formatDimension(config.nodeWidth),
height: formatDimension(config.nodeHeight),
}}
>
{
customNode
? customNode({ collapsed: node.data._collapsed, data: node.data })
: <span>{node.data.value}</span>
}
</div>
})
}
</CSSTransitionGroup>
</div >
</div >
});
export default TreeChart;
================================================
FILE: packages/react-tree-chart/src/tree-chart/typings.d.ts
================================================
declare module 'react-transition-group'
================================================
FILE: packages/react-tree-chart/tsconfig.json
================================================
{
"compilerOptions": {
"target": "es5",
"declaration": true,
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx"
},
"include": [
"src/tree-chart"
]
}
================================================
FILE: packages/tree-chart-core/.eslintrc.js
================================================
module.exports = {
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module",
ecmaVersion: 2015
}
}
================================================
FILE: packages/tree-chart-core/.gitignore
================================================
build
================================================
FILE: packages/tree-chart-core/package.json
================================================
{
"name": "@ssthouse/tree-chart-core",
"version": "1.2.0",
"description": "tree chart's core logic (shared by Vue2,Vue3,React)",
"main": "build/index.js",
"module": "build/index.js",
"scripts": {
"build": "rm -rf build && npx tsc --declaration true",
"release": "npm run build && ../../scripts/publish-safe.sh"
},
"author": "ssthouse",
"license": "ISC",
"dependencies": {
"d3": "^7.2.0"
},
"devDependencies": {
"eslint": "^8.4.1",
"typescript": "^4.5.2"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
}
}
================================================
FILE: packages/tree-chart-core/src/base/uuid.ts
================================================
export function uuid(): string {
const s = []
const hexDigits = '0123456789abcdef'
for (let i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
}
s[14] = '4'
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1)
s[8] = s[13] = s[18] = s[23] = '-'
return s.join('')
}
================================================
FILE: packages/tree-chart-core/src/index.ts
================================================
import TreeChartCore from "./tree-chart/index";
export default TreeChartCore;
export * from './tree-chart/constant';
export * from './tree-chart/tree-chart';
================================================
FILE: packages/tree-chart-core/src/tree-chart/constant.ts
================================================
export const DEFAULT_NODE_WIDTH = 100;
export const DEFAULT_NODE_HEIGHT = 100;
export const DEFAULT_LEVEL_HEIGHT = 200;
/**
* Used to decrement the height of the 'initTransformY' to center diagrams.
* This is only a hotfix caused by the addition of '__invisible_root' node
* for multi root purposes.
*/
export const DEFAULT_HEIGHT_DECREMENT = 200;
export const ANIMATION_DURATION = 800;
export const MATCH_TRANSLATE_REGEX = /translate\((-?\d+)px, ?(-?\d+)px\)/i;
export const MATCH_SCALE_REGEX = /scale\((\S*)\)/i;
================================================
FILE: packages/tree-chart-core/src/tree-chart/index.ts
================================================
import * as d3 from 'd3';
import { ANIMATION_DURATION, DEFAULT_HEIGHT_DECREMENT, DEFAULT_LEVEL_HEIGHT, DEFAULT_NODE_HEIGHT, DEFAULT_NODE_WIDTH, MATCH_SCALE_REGEX, MATCH_TRANSLATE_REGEX } from './constant';
import { TreeDataset, Direction, TreeLinkStyle } from './tree-chart';
import { deepCopy, rotatePoint } from './util';
interface TreeConfig {
nodeWidth: number;
nodeHeight: number;
levelHeight: number;
}
interface TreeChartCoreParams {
treeConfig?: TreeConfig;
linkStyle?: TreeLinkStyle;
direction?: Direction;
collapseEnabled: boolean;
dataset: TreeDataset;
svgElement: SVGElement;
domElement: HTMLDivElement;
treeContainer: HTMLDivElement;
}
export default class TreeChartCore {
treeConfig: TreeConfig = {
nodeWidth: DEFAULT_NODE_WIDTH,
nodeHeight: DEFAULT_NODE_HEIGHT,
levelHeight: DEFAULT_LEVEL_HEIGHT,
};
linkStyle: TreeLinkStyle = TreeLinkStyle.CURVE;
direction: Direction = Direction.VERTICAL;
collapseEnabled: boolean = true
dataset: TreeDataset;
svgElement: SVGElement;
svgSelection: any;
domElement: HTMLDivElement;
treeContainer: HTMLDivElement;
nodeDataList: any[];
linkDataList: any[];
initTransformX: number;
initTransformY: number;
currentScale: number = 1;
constructor(params: TreeChartCoreParams) {
if (params.treeConfig) {
this.treeConfig = params.treeConfig;
}
this.collapseEnabled = params.collapseEnabled
this.svgElement = params.svgElement;
this.domElement = params.domElement;
this.treeContainer = params.treeContainer;
this.dataset = this.updatedInternalData(params.dataset);
if (params.direction) this.direction = params.direction;
if (params.linkStyle) this.linkStyle = params.linkStyle
}
init() {
this.draw();
this.enableDrag();
this.initTransform();
}
getNodeDataList() {
return this.nodeDataList;
}
getInitialTransformStyle(): Record<string, string> {
return {
transform: `scale(1) translate(${this.initTransformX}px, ${this.initTransformY}px)`,
transformOrigin: "center",
};
}
zoomIn() {
const originTransformStr = this.domElement.style.transform;
// 如果已有scale属性, 在原基础上修改
let targetScale = 1 * 1.2;
const scaleMatchResult = originTransformStr.match(MATCH_SCALE_REGEX);
if (scaleMatchResult && scaleMatchResult.length > 0) {
const originScale = parseFloat(scaleMatchResult[1]);
targetScale *= originScale;
}
this.setScale(targetScale);
}
zoomOut() {
const originTransformStr = this.domElement.style.transform;
// 如果已有scale属性, 在原基础上修改
let targetScale = 1 / 1.2;
const scaleMatchResult = originTransformStr.match(MATCH_SCALE_REGEX);
if (scaleMatchResult && scaleMatchResult.length > 0) {
const originScale = parseFloat(scaleMatchResult[1]);
targetScale = originScale / 1.2;
}
this.setScale(targetScale);
}
restoreScale() {
this.setScale(1);
}
setScale(scaleNum) {
if (typeof scaleNum !== "number") return;
let pos = this.getTranslate();
let translateString = `translate(${pos[0]}px, ${pos[1]}px)`;
this.svgElement.style.transform = `scale(${scaleNum}) ` + translateString;
this.domElement.style.transform =
`scale(${scaleNum}) ` + translateString;
this.currentScale = scaleNum;
}
getTranslate() {
let string = this.svgElement.style.transform;
let match = string.match(MATCH_TRANSLATE_REGEX);
if (match === null) {
return [null, null];
}
let x = parseInt(match[1]);
let y = parseInt(match[2]);
return [x, y];
}
isVertical() {
return this.direction === Direction.VERTICAL;
}
/**
* 根据link数据,生成svg path data
*/
private generateLinkPath(d) {
const self = this;
if (this.linkStyle === TreeLinkStyle.CURVE) {
return this.generateCurceLinkPath(self, d);
}
if (this.linkStyle === TreeLinkStyle.STRAIGHT) {
// the link path is: source -> secondPoint -> thirdPoint -> target
return this.generateStraightLinkPath(d);
}
}
private generateCurceLinkPath(self: this, d: any) {
const isVertical = this.isVertical();
const linkPath = isVertical
? d3.linkVertical()
: d3.linkHorizontal();
linkPath
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
})
.source(function (d) {
const sourcePoint = {
x: d.source.x,
y: d.source.y,
};
return self.direction === Direction.VERTICAL
? sourcePoint
: rotatePoint(sourcePoint);
})
.target(function (d) {
const targetPoint = {
x: d.target.x,
y: d.target.y,
};
return self.direction === Direction.VERTICAL
? targetPoint
: rotatePoint(targetPoint);
});
return linkPath(d);
}
private generateStraightLinkPath(d: any) {
const linkPath = d3.path();
let sourcePoint = { x: d.source.x, y: d.source.y };
let targetPoint = { x: d.target.x, y: d.target.y };
if (!this.isVertical()) {
sourcePoint = rotatePoint(sourcePoint);
targetPoint = rotatePoint(targetPoint);
}
const xOffset = targetPoint.x - sourcePoint.x;
const yOffset = targetPoint.y - sourcePoint.y;
const secondPoint = this.isVertical()
? { x: sourcePoint.x, y: sourcePoint.y + yOffset / 2 }
: { x: sourcePoint.x + xOffset / 2, y: sourcePoint.y };
const thirdPoint = this.isVertical()
? { x: targetPoint.x, y: sourcePoint.y + yOffset / 2 }
: { x: sourcePoint.x + xOffset / 2, y: targetPoint.y };
linkPath.moveTo(sourcePoint.x, sourcePoint.y);
linkPath.lineTo(secondPoint.x, secondPoint.y);
linkPath.lineTo(thirdPoint.x, thirdPoint.y);
linkPath.lineTo(targetPoint.x, targetPoint.y);
return linkPath.toString();
}
updateDataList() {
let [nodeDataList, linkDataList] = this.buildTree()
nodeDataList.splice(0, 1);
linkDataList = linkDataList.filter(
(x) => x.source.data.name !== "__invisible_root"
);
this.linkDataList = linkDataList;
this.nodeDataList = nodeDataList;
}
private draw() {
this.updateDataList();
const identifier = this.dataset["identifier"];
const specialLinks = this.dataset["links"];
if (specialLinks && identifier) {
for (const link of specialLinks) {
let parent,
children = undefined;
if (identifier === "value") {
parent = this.nodeDataList.find((d) => {
return d[identifier] == link.parent;
});
children = this.nodeDataList.filter((d) => {
return d[identifier] == link.child;
});
} else {
parent = this.nodeDataList.find((d) => {
return d["data"][identifier] == link.parent;
});
children = this.nodeDataList.filter((d) => {
return d["data"][identifier] == link.child;
});
}
if (parent && children) {
for (const child of children) {
const new_link = {
source: parent,
target: child,
};
this.linkDataList.push(new_link);
}
}
}
}
this.svgSelection = d3.select(this.svgElement);
const self = this;
const links = this.svgSelection
.selectAll(".link")
.data(this.linkDataList, (d) => {
return `${d.source.data._key}-${d.target.data._key}`;
});
links
.enter()
.append("path")
.style("opacity", 0)
.transition()
.duration(ANIMATION_DURATION)
.ease(d3.easeCubicInOut)
.style("opacity", 1)
.attr("class", "link")
.attr("d", function (d) {
return self.generateLinkPath(d);
});
links
.transition()
.duration(ANIMATION_DURATION)
.ease(d3.easeCubicInOut)
.attr("d", function (d) {
return self.generateLinkPath(d);
});
links
.exit()
.transition()
.duration(ANIMATION_DURATION / 2)
.ease(d3.easeCubicInOut)
.style("opacity", 0)
.remove();
}
/**
* Returns updated dataset by deep copying every nodes from the externalData and adding unique '_key' attributes.
**/
private updatedInternalData(externalData) {
var data = { name: "__invisible_root", children: [] };
if (!externalData) return data;
if (Array.isArray(externalData)) {
for (var i = externalData.length - 1; i >= 0; i--) {
data.children.push(deepCopy(externalData[i]));
}
} else {
data.children.push(deepCopy(externalData));
}
return data;
}
private buildTree() {
const treeBuilder = d3
.tree()
.nodeSize([this.treeConfig.nodeWidth, this.treeConfig.levelHeight]);
const tree = treeBuilder(d3.hierarchy(this.dataset));
return [tree.descendants(), tree.links()];
}
private enableDrag() {
let startX = 0;
let startY = 0;
let isDrag = false;
// 保存鼠标点下时的位移
let mouseDownTransform = "";
this.treeContainer.onmousedown = (event) => {
mouseDownTransform = this.svgElement.style.transform;
startX = event.clientX;
startY = event.clientY;
isDrag = true;
};
this.treeContainer.onmousemove = (event) => {
if (!isDrag) return;
const originTransform = mouseDownTransform;
let originOffsetX = 0;
let originOffsetY = 0;
if (originTransform) {
const result = originTransform.match(MATCH_TRANSLATE_REGEX);
if (result !== null && result.length !== 0) {
const [offsetX, offsetY] = result.slice(1);
originOffsetX = parseInt(offsetX);
originOffsetY = parseInt(offsetY);
}
}
let newX =
Math.floor((event.clientX - startX) / this.currentScale) +
originOffsetX;
let newY =
Math.floor((event.clientY - startY) / this.currentScale) +
originOffsetY;
let transformStr = `translate(${newX}px, ${newY}px)`;
if (originTransform) {
transformStr = originTransform.replace(
MATCH_TRANSLATE_REGEX,
transformStr
);
}
this.svgElement.style.transform = transformStr;
this.domElement.style.transform = transformStr;
};
this.treeContainer.onmouseup = () => {
startX = 0;
startY = 0;
isDrag = false;
};
}
initTransform() {
const containerWidth = this.domElement.offsetWidth;
const containerHeight = this.domElement.offsetHeight;
if (this.isVertical()) {
this.initTransformX = Math.floor(containerWidth / 2);
this.initTransformY = Math.floor(
this.treeConfig.nodeHeight - DEFAULT_HEIGHT_DECREMENT
);
} else {
this.initTransformX = Math.floor(
this.treeConfig.nodeWidth - DEFAULT_HEIGHT_DECREMENT
);
this.initTransformY = Math.floor(containerHeight / 2);
}
}
onClickNode(index: number) {
if (this.collapseEnabled) {
const curNode = this.nodeDataList[index];
if (curNode.data.children) {
curNode.data._children = curNode.data.children;
curNode.data.children = null;
curNode.data._collapsed = true;
} else {
curNode.data.children = curNode.data._children;
curNode.data._children = null;
curNode.data._collapsed = false;
}
this.draw();
}
}
/**
* call this function to update dataset
* notice : you need to update the view rendered by `nodeDataList` too
* @param dataset the new dataset to show in chart
*/
updateDataset(dataset: TreeDataset) {
this.dataset = this.updatedInternalData(dataset);
this.draw();
}
/**
* call this function to update direction
* notice : you need to update the view rendered by `nodeDataList` and `initialTransformStyle` too
* @param direction the new direction to show in chart
*/
updateDirection(direction: Direction) {
this.direction = direction;
this.initTransform();
this.updateLinks();
}
/**
* Update link paths without rebuilding the tree
* This is used when direction changes but node positions remain the same
*/
private updateLinks() {
if (!this.svgSelection) {
this.svgSelection = d3.select(this.svgElement);
}
if (!this.linkDataList || this.linkDataList.length === 0) {
return;
}
const self = this;
// 重新绑定数据并更新连接线路径
const linkSelection = this.svgSelection
.selectAll(".link")
.data(this.linkDataList, (d) => {
return `${d.source.data._key}-${d.target.data._key}`;
});
// 更新已存在的连接线
linkSelection
.transition()
.duration(ANIMATION_DURATION)
.ease(d3.easeCubicInOut)
.attr("d", function (d) {
return self.generateLinkPath(d);
});
// 处理新添加的连接线(虽然不应该有,但为了安全)
const newLinks = linkSelection
.enter()
.append("path")
.style("opacity", 0)
.attr("class", "link");
if (newLinks.size() > 0) {
newLinks
.transition()
.duration(ANIMATION_DURATION)
.ease(d3.easeCubicInOut)
.style("opacity", 1)
.attr("d", function (d) {
return self.generateLinkPath(d);
});
}
}
/**
* release all dom reference
*/
destroy() {
this.svgElement = null;
this.domElement = null;
this.treeContainer = null;
}
}
================================================
FILE: packages/tree-chart-core/src/tree-chart/tree-chart.ts
================================================
export enum Direction {
VERTICAL = "vertical",
HORIZONTAL = "horizontal",
}
export enum TreeLinkStyle {
CURVE = "curve",
STRAIGHT = "straight",
}
export type TreeDataset = Object | Object[];
================================================
FILE: packages/tree-chart-core/src/tree-chart/util.ts
================================================
import { uuid } from "../base/uuid";
export function rotatePoint({ x, y }: { x: number; y: number }) {
return {
x: y,
y: x,
};
}
/**
* Returns a deep copy of selected node (copy of itself and it's children).
* If selected node or it's children have no '_key' attribute it will assign a new one.
**/
export function deepCopy(node) {
let obj = { _key: uuid() };
for (var key in node) {
if (node[key] === null) {
obj[key] = null;
} else if (Array.isArray(node[key])) {
obj[key] = node[key].map((x) => deepCopy(x));
} else if (typeof node[key] === "object") {
obj[key] = deepCopy(node[key]);
} else {
obj[key] = node[key];
}
}
return obj;
}
================================================
FILE: packages/tree-chart-core/tsconfig.json
================================================
{
"compilerOptions": {
"outDir": "./build/",
"sourceMap": false,
"strict": false,
"noImplicitReturns": true,
"module": "es2015",
"lib": ["es2015", "DOM"],
"moduleResolution": "node",
"target": "es5"
},
"include": ["src/**/*"]
}
================================================
FILE: packages/tree-chart-demo/build/webpack.config.base.js
================================================
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/demo/main.ts',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.vue$/,
use: ['vue-loader']
},
{
test: /\.ts$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/]
}
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './template/index.html',
inject: true
})
],
resolve: {
extensions: ['.ts', '.js', '.vue', '.json'],
alias: {
vue$: 'vue/dist/vue.esm.js'
}
}
}
================================================
FILE: packages/tree-chart-demo/build/webpack.config.dev.js
================================================
const merge = require('webpack-merge')
module.exports = merge(require('./webpack.config.base'), {
mode: 'development',
output: {
publicPath: '/'
},
devtool: 'source-map'
})
================================================
FILE: packages/tree-chart-demo/build/webpack.config.prod.js
================================================
const merge = require('webpack-merge')
const webpack = require('webpack')
module.exports = merge(require('./webpack.config.base'), {
mode: 'production',
devtool: 'source-map',
output: {
publicPath: './'
},
optimization: {
minimize: true
}
})
================================================
FILE: packages/tree-chart-demo/package.json
================================================
{
"name": "tree-chart-demo",
"version": "0.1.0",
"description": "tree chart demo page",
"main": "index.js",
"author": "ssthouse",
"license": "ISC",
"dependencies": {
"@ssthouse/vue-tree-chart": "^0.5.4",
"d3": "^7.1.1",
"vue": "2.6.8",
"vue-router": "^3.5.3",
"vuetify": "^1.0.18"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^5.0.2",
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
"babel-eslint": "^8.2.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.1",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "^6.5.0",
"eslint": "^8.1.0",
"eslint-config-standard": "^10.2.1",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-node": "^5.2.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-promise": "^3.4.0",
"eslint-plugin-standard": "^3.0.1",
"eslint-plugin-vue": "^6.0.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.4",
"html-webpack-plugin": "^5.5.0",
"husky": "^7.0.4",
"lerna": "^4.0.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"lint-staged": "^10.2.11",
"node-notifier": "^8.0.1",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"ora": "^1.2.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^6.2.0",
"postcss-url": "^7.2.1",
"prettier": "^2.0.5",
"rimraf": "^2.6.0",
"semver": "^5.3.0",
"shelljs": "^0.8.5",
"style-loader": "^3.3.1",
"ts-loader": "^9.2.6",
"typescript": "^3.3.3333",
"uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^4.1.1",
"vue-class-component": "^7.0.1",
"vue-loader": "^15.7.0",
"vue-property-decorator": "^8.0.0",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "2.6.8",
"webpack": "^5.61.0",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.4.0",
"webpack-merge": "^4.1.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"prettier": {
"#": "prettier config in here :)",
"singleQuote": true,
"semi": false,
"arrowParens": "always",
"space-before-function-paren": "off",
"trailingComma": "none"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.js": [
"eslint",
"prettier --write"
],
"*.vue": [
"eslint",
"prettier --write"
]
}
}
================================================
FILE: packages/tree-chart-demo/src/base/color-util.ts
================================================
export function randomColor(): string {
const letters = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f'
]
let color = '#'
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)]
}
return color
}
function appendFront0(numStr: string): string {
return numStr.padStart(2, '0')
}
export function getColorStrFromCanvas(
context: any,
xIndex: number,
yIndex: number
): string {
const pixelData = context.getImageData(xIndex, yIndex, 1, 1).data
const [r, g, b] = pixelData
return (
'#' +
appendFront0(r.toString(16)) +
appendFront0(g.toString(16)) +
appendFront0(b.toString(16))
)
}
================================================
FILE: packages/tree-chart-demo/src/base/data-generator.ts
================================================
export interface Data {
name: string
title: string
children: any
}
export function generateOrgChartData(depth: number) {
const data: Data = {
name: 'Lao Lao',
title: 'general manager',
children: [
{ name: 'Bo Miao', title: 'department manager' },
{
name: 'Su Miao',
title: 'department manager',
children: [
{ name: 'Tie Hua', title: 'senior engineer' },
{
name: 'Hei Hei',
title: 'senior engineer',
children: [
{ name: 'Pang Pang', title: 'engineer' },
{ name: 'Xiang Xiang', title: 'UE engineer' }
]
}
]
},
{ name: 'Hong Miao', title: 'department manager' }
]
}
for (let i = 0; i < 3; i++) {
data['children'].push({
name: 'Lao Lao',
title: 'general manager',
children: [
{ name: 'Bo Miao', title: 'department manager' },
{
name: 'Su Miao',
title: 'department manager',
children: [{ name: 'Tie Hua', title: 'senior engineer' }]
}
]
})
}
let temp = data
for (let i = 0; i < depth; i++) {
if (!temp.children) {
temp.children = []
}
temp.children.push({
name: 'Lao Lao',
title: 'general manager',
children: [
{ name: 'Bo Miao', title: 'department manager' },
{
name: 'Su Miao',
title: 'department manager',
children: [
{ name: 'Tie Hua', title: 'senior engineer' },
{
name: 'Hei Hei',
title: 'senior engineer',
children: [{ name: 'Xiang Xiang', title: 'UE engineer' }]
}
]
}
]
})
temp = temp.children[0]
}
return data
}
export function generateOrgChartDataFolded(depth: any, foldDepth: number) {
const data = this.generateOrgChartData(depth)
let tempNode = data
for (let i = 0; i < foldDepth && tempNode.children; i++) {
tempNode = tempNode.children[0]
}
tempNode._children = tempNode.children
tempNode.children = null
return data
}
================================================
FILE: packages/tree-chart-demo/src/base/utils.ts
================================================
function text(ctx, text, x: number, y: number, fontSize, fontColor: string) {
ctx.font = '14px Arial'
ctx.fillStyle = fontColor
ctx.fillText(text, x, y)
}
function wrapText(
context,
text: string,
x: number,
y: number,
maxWidth: number,
lineHeight: number,
fontColor: string
) {
context.fillStyle = fontColor
const words = text.split(' ')
let line = ''
for (let n = 0; n < words.length; n++) {
let testLine = `${line + words[n]} `
let metrics = context.measureText(testLine)
let testWidth = metrics.width
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, y)
line = `${words[n]} `
y += lineHeight
} else {
line = testLine
}
}
context.fillText(line, x, y)
}
function roundRect(
context: CanvasRenderingContext2D,
x: number,
y: number,
width: number,
height: number,
radius: any,
fill: boolean,
stroke: boolean
): void {
if (typeof stroke === 'undefined') {
stroke = true
}
if (typeof radius === 'undefined') {
radius = 5
}
if (typeof radius === 'number') {
radius = { tl: radius, tr: radius, br: radius, bl: radius }
} else {
let defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 }
for (let side in defaultRadius) {
radius[side] = radius[side] || defaultRadius[side]
}
}
context.beginPath()
context.moveTo(x + radius.tl, y)
context.lineTo(x + width - radius.tr, y)
context.quadraticCurveTo(x + width, y, x + width, y + radius.tr)
context.lineTo(x + width, y + height - radius.br)
context.quadraticCurveTo(
x + width,
y + height,
x + width - radius.br,
y + height
)
context.lineTo(x + radius.bl, y + height)
context.quadraticCurveTo(x, y + height, x, y + height - radius.bl)
context.lineTo(x, y + radius.tl)
context.quadraticCurveTo(x, y, x + radius.tl, y)
context.closePath()
if (fill) {
context.fill()
}
if (stroke) {
context.stroke()
}
}
export default {
text,
wrapText,
roundRect
}
================================================
FILE: packages/tree-chart-demo/src/base/uuid.ts
================================================
export function uuid(): string {
const s = []
const hexDigits = '0123456789abcdef'
for (let i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
}
s[14] = '4'
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1)
s[8] = s[13] = s[18] = s[23] = '-'
return s.join('')
}
================================================
FILE: packages/tree-chart-demo/src/components/CanvasTree.vue
================================================
<template>
<div id="org-chart-container">
<div class="menu-container">
<v-layout row>
<v-btn @click="bigger()">+</v-btn>
<v-btn @click="smaller()">-</v-btn>
</v-layout>
<v-card>
<v-card-title>
<div slot="header" class="action-title">
<span>Support actions</span>
</div>
<div
v-for="action in supportActions"
:key="action"
class="action-item"
>
{{ '* ' + action }}
</div>
</v-card-title>
</v-card>
</div>
</div>
</template>
<script lang="ts">
import OrgChart from './org-chart'
import Vue from 'vue'
import { generateOrgChartData, Data } from '../base/data-generator'
export default Vue.extend({
name: 'org-chart',
data() {
return {
data: null,
orgChart: null,
supportActions: [
'click node to toggle',
'drag canvas',
'use mouse wheel to zoom',
'button control to zoom'
]
}
},
created() {
this.data = generateOrgChartData(10)
},
mounted() {
this.orgChart = new OrgChart()
this.orgChart.draw(this.data)
},
methods: {
test() {
this.orgChart.draw(this.data)
},
bigger() {
this.orgChart.bigger()
},
smaller() {
this.orgChart.smaller()
}
}
})
</script>
<style scoped>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.orgChart {
border: 1px solid black;
height: 100%;
}
.menu-container {
position: absolute;
padding-top: 16px;
padding-left: 16px;
padding-right: 16px;
padding-bottom: 156px;
display: flex;
align-items: center;
flex-direction: column;
vertical-align: top;
width: 400px;
height: 100%;
background-color: rgba(238, 237, 236, 0.5);
}
.action-title {
font-size: 28px;
}
.action-item {
font-size: 24px;
}
</style>
================================================
FILE: packages/tree-chart-demo/src/components/VueTreeDemo.vue
================================================
<template>
<div class="container">
<h3>Basic usage | 基本使用</h3>
<vue-tree
style="width: 800px; height: 600px; border: 1px solid gray;"
:dataset="sampleData"
:config="treeConfig"
>
</vue-tree>
<h3>Show different style with folded nodes | 异化展示折叠节点</h3>
<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>
<h3>Rich media tree chart | 富媒体树状图</h3>
<vue-tree
style="width: 800px; 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>
<h3>Link nodes with straight line | 直线连接</h3>
<vue-tree
style="width: 800px; height: 600px; border: 1px solid gray;"
:dataset="richMediaData"
:config="treeConfig"
linkStyle="straight"
>
<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>
<h3>Horizontal tree chart | 横向树状图</h3>
<vue-tree
style="width: 800px; height: 600px; border: 1px solid gray;"
:dataset="richMediaData"
:config="treeConfig"
direction="horizontal"
>
<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>
<h3>Toggle Direction | 切换方向</h3>
<div style="display: flex; align-items: center; gap: 16px; margin-bottom: 16px;">
<v-btn @click="toggleDirection" color="primary">
切换方向 (当前: {{ currentDirection === 'vertical' ? '垂直' : '水平' }})
</v-btn>
<span>Direction: {{ currentDirection }}</span>
</div>
<vue-tree
ref="directionTree"
style="width: 800px; height: 600px; border: 1px solid gray;"
:dataset="richMediaData"
:config="treeConfig"
:direction="currentDirection"
>
<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>
<h3>Zoom in or out | 缩放</h3>
<div style="display: flex;">
<v-btn @click="controlScale('bigger')">+</v-btn>
<v-btn @click="controlScale('smaller')">-</v-btn>
<v-btn @click="controlScale('restore')">1:1</v-btn>
</div>
<vue-tree
ref="scaleTree"
style="width: 800px; 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>
<h3>
Example of multiple parents with node collapse disabled |
支持多父节点(禁用折叠)
</h3>
<vue-tree
style="width: 800px; height: 600px; border: 1px solid gray;"
:dataset="vehicules"
:config="treeConfig"
:collapse-enabled="false"
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>
<h3>
Example of multi-root with changing dataset | 多根节点, 支持切换数据源
</h3>
<button type="button" class="changeDataset" v-on:click="clicked = !clicked">
Change dataset
</button>
<vue-tree
style="width: 800px; height: 600px; border: 1px solid gray;"
:dataset="multiRootChoice"
:config="treeConfig"
:collapse-enabled="true"
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>
import VueTree from '@ssthouse/vue-tree-chart'
export default {
name: 'treemap',
components: { 'vue-tree': VueTree },
data() {
return {
sampleData: {
value: '1',
children: [
{ value: '2', children: [{ value: '4' }, { value: '5' }] },
{ value: '3' }
]
},
richMediaData: {
name: 'James',
value: 800,
avatar:
'https://live.yworks.com/demos/complete/interactiveorgchart/resources/usericon_female3.svg',
children: [
{
name: 'Bob',
value: 400,
avatar:
'https://live.yworks.com/demos/complete/interactiveorgchart/resources/usericon_male4.svg',
children: [
{
name: 'C1',
value: 100,
avatar:
'https://live.yworks.com/demos/complete/interactiveorgchart/resources/usericon_female4.svg'
},
{
name: 'C2',
value: 300,
avatar:
'https://live.yworks.com/demos/complete/interactiveorgchart/resources/usericon_male2.svg'
},
{
name: 'C3',
value: 200,
avatar:
'https://live.yworks.com/demos/complete/interactiveorgchart/resources/usericon_male3.svg'
}
]
},
{
name: 'Smith',
value: 200,
avatar:
'https://live.yworks.com/demos/complete/interactiveorgchart/resources/usericon_male3.svg',
children: [
{
name: 'S1',
value: 230,
avatar:
'https://live.yworks.com/demos/complete/interactiveorgchart/resources/usericon_female1.svg'
}
]
},
{
name: 'Jackson',
value: 300,
avatar:
'https://live.yworks.com/demos/complete/interactiveorgchart/resources/usericon_female3.svg'
}
]
},
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'
},
clicked: false,
currentDirection: 'vertical',
multiRoot1: [
{
name: 'Wheels',
children: [
{
name: 'Wings',
children: [
{
name: 'Plane'
}
]
}
]
},
{
name: 'Wings',
children: [
{
name: 'Plane'
}
]
}
],
multiRoot2: {
name: 'Carburetor',
children: [
{
name: 'Truck',
customID: 2
},
{
name: 'Car',
customID: 2
}
]
},
treeConfig: { nodeWidth: 120, nodeHeight: 80, levelHeight: 200 }
}
},
computed: {
multiRootChoice() {
if (this.clicked) {
return this.multiRoot2
}
return this.multiRoot1
}
},
methods: {
controlScale(command) {
switch (command) {
case 'bigger':
this.$refs.scaleTree.zoomIn()
break
case 'smaller':
this.$refs.scaleTree.zoomOut()
break
case 'restore':
this.$refs.scaleTree.restoreScale()
break
}
},
toggleDirection() {
this.currentDirection = this.currentDirection === 'vertical' ? 'horizontal' : 'vertical'
}
}
}
</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;
}
.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;
}
h3 {
margin-top: 32px;
margin-bottom: 16px;
}
.changeDataset {
font-size: 1rem;
font-weight: 200;
letter-spacing: 1px;
padding: 10px 45px 10px;
outline: 0;
border: 1px solid black;
cursor: pointer;
margin: 1rem;
position: relative;
background-color: rgb(33, 150, 243);
color: whitesmoke;
}
</style>
================================================
FILE: packages/tree-chart-demo/src/components/org-chart.ts
================================================
import * as d3 from 'd3'
import Util from '../base/utils'
import { randomColor, getColorStrFromCanvas } from '../base/color-util'
class OrgChart {
d3: any
width: number
height: number
padding: number
nodeWidth: number
nodeHeight: number
unitPadding: number
unitWidth: number
unitHeight: number
duration: number
scale: number
data: any
treeGenerator: any
treeData: any
virtualContainerNode: any
container: any
canvasNode: any
hiddenCanvasNode: any
context: any
hiddenContext: any
colorNodeMap: {}
onDrag_: boolean
dragStartPoint_: { x: number; y: number }
constructor() {
this.d3 = d3
this.init()
}
init() {
this.initVariables()
this.initCanvas()
this.initVirtualNode()
this.setCanvasListener()
}
initVariables() {
this.width = window.innerWidth
this.height = window.innerHeight
this.padding = 20
// tree node size
this.nodeWidth = 180
this.nodeHeight = 280
// org unit size
this.unitPadding = 20
this.unitWidth = 140
this.unitHeight = 100
// animation duration
this.duration = 600
this.scale = 1.0
}
draw(data) {
this.data = this.d3.hierarchy(data)
this.treeGenerator = this.d3
.tree()
.nodeSize([this.nodeWidth, this.nodeHeight])
this.update(null)
const self = this
this.d3.timer(function () {
self.drawCanvas()
})
}
update(targetTreeNode) {
this.treeData = this.treeGenerator(this.data)
const nodes = this.treeData.descendants()
const links = this.treeData.links()
let animatedStartX = 0
let animatedStartY = 0
let animatedEndX = 0
let animatedEndY = 0
if (targetTreeNode) {
animatedStartX = targetTreeNode.x0
animatedStartY = targetTreeNode.y0
animatedEndX = targetTreeNode.x
animatedEndY = targetTreeNode.y
}
this.updateOrgUnits(
nodes,
animatedStartX,
animatedStartY,
animatedEndX,
animatedEndY
)
this.updateLinks(
links,
animatedStartX,
animatedStartY,
animatedEndX,
animatedEndY
)
this.addColorKey()
this.bindNodeToTreeData()
}
updateOrgUnits(
nodes,
animatedStartX,
animatedStartY,
animatedEndX,
animatedEndY
) {
let orgUnitSelection = this.virtualContainerNode
.selectAll('.orgUnit')
.data(nodes, (d) => d['colorKey'])
orgUnitSelection
.attr('class', 'orgUnit')
.attr('x', function (data) {
return data.x0
})
.attr('y', function (data) {
return data.y0
})
.transition()
.duration(this.duration)
.attr('x', function (data) {
return data.x
})
.attr('y', function (data) {
return data.y
})
.attr('fillStyle', '#ff0000')
orgUnitSelection
.enter()
.append('orgUnit')
.attr('class', 'orgUnit')
.attr('x', animatedStartX)
.attr('y', animatedStartY)
.transition()
.duration(this.duration)
.attr('x', function (data) {
return data.x
})
.attr('y', function (data) {
return data.y
})
.attr('fillStyle', '#ff0000')
orgUnitSelection
.exit()
.transition()
.duration(this.duration)
.attr('x', animatedEndX)
.attr('y', animatedEndY)
.remove()
// record origin index for animation
nodes.forEach((treeNode) => {
treeNode['x0'] = treeNode.x
treeNode['y0'] = treeNode.y
})
orgUnitSelection = null
}
updateLinks(
links,
animatedStartX,
animatedStartY,
animatedEndX,
animatedEndY
) {
let linkSelection = this.virtualContainerNode
.selectAll('.link')
.data(links, function (d) {
return d.source['colorKey'] + ':' + d.target['colorKey']
})
linkSelection
.attr('class', 'link')
.attr('sourceX', function (linkData) {
return linkData.source['x00']
})
.attr('sourceY', function (linkData) {
return linkData.source['y00']
})
.attr('targetX', function (linkData) {
return linkData.target['x00']
})
.attr('targetY', function (linkData) {
return linkData.target['y00']
})
.transition()
.duration(this.duration)
.attr('sourceX', function (linkData) {
return linkData.source.x
})
.attr('sourceY', function (linkData) {
return linkData.source.y
})
.attr('targetX', function (linkData) {
return linkData.target.x
})
.attr('targetY', function (linkData) {
return linkData.target.y
})
linkSelection
.enter()
.append('link')
.attr('class', 'link')
.attr('sourceX', animatedStartX)
.attr('sourceY', animatedStartY)
.attr('targetX', animatedStartX)
.attr('targetY', animatedStartY)
.transition()
.duration(this.duration)
.attr('sourceX', function (link) {
return link.source.x
})
.attr('sourceY', function (link) {
return link.source.y
})
.attr('targetX', function (link) {
return link.target.x
})
.attr('targetY', function (link) {
return link.target.y
})
linkSelection
.exit()
.transition()
.duration(this.duration)
.attr('sourceX', animatedEndX)
.attr('sourceY', animatedEndY)
.attr('targetX', animatedEndX)
.attr('targetY', animatedEndY)
.remove()
// record origin data for animation
links.forEach((treeNode) => {
treeNode.source['x00'] = treeNode.source.x
treeNode.source['y00'] = treeNode.source.y
treeNode.target['x00'] = treeNode.target.x
treeNode.target['y00'] = treeNode.target.y
})
linkSelection = null
}
initCanvas() {
this.container = this.d3.select('#org-chart-container')
this.canvasNode = this.container
.append('canvas')
.attr('class', 'orgChart')
.attr('width', this.width)
.attr('height', this.height)
this.hiddenCanvasNode = this.container
.append('canvas')
.attr('class', 'orgChart')
.attr('width', this.width)
.attr('height', this.height)
.style('display', '')
this.context = this.canvasNode.node().getContext('2d')
this.context.translate(this.width / 2, this.padding)
this.hiddenContext = this.hiddenCanvasNode.node().getContext('2d')
this.hiddenContext.translate(this.width / 2, this.padding)
}
initVirtualNode() {
let virtualContainer = document.createElement('root')
this.virtualContainerNode = this.d3.select(virtualContainer)
this.colorNodeMap = {}
}
addColorKey() {
// give each node a unique color
const self = this
this.virtualContainerNode.selectAll('.orgUnit').each(function () {
const node = self.d3.select(this)
let newColor = randomColor()
while (self.colorNodeMap[newColor]) {
newColor = randomColor()
}
node.attr('colorKey', newColor)
node.data()[0]['colorKey'] = newColor
self.colorNodeMap[newColor] = node
})
}
bindNodeToTreeData() {
// give each node a unique color
const self = this
this.virtualContainerNode.selectAll('.orgUnit').each(function () {
const node = self.d3.select(this)
const data = node.data()[0]
data.node = node
})
}
drawCanvas() {
this.drawShowCanvas()
this.drawHiddenCanvas()
}
drawShowCanvas() {
this.context.clearRect(-50000, -10000, 100000, 100000)
const self = this
// draw links
this.virtualContainerNode.selectAll('.link').each(function () {
const node = self.d3.select(this)
const linkPath = self.d3
.linkVertical()
.x(function (d) {
return d.x
})
.y(function (d) {
return d.y
})
.source(function () {
return { x: node.attr('sourceX'), y: node.attr('sourceY') }
})
.target(function () {
return { x: node.attr('targetX'), y: node.attr('targetY') }
})
const path = new Path2D(linkPath())
self.context.stroke(path)
})
this.virtualContainerNode.selectAll('.orgUnit').each(function () {
const node = self.d3.select(this)
const treeNode = node.data()[0]
const data = treeNode.data
self.context.fillStyle = '#3ca0ff'
const indexX = Number(node.attr('x')) - self.unitWidth / 2
const indexY = Number(node.attr('y')) - self.unitHeight / 2
// draw unit outline rect (if you want to modify this line ===> please modify the same line in `drawHiddenCanvas`)
Util.roundRect(
self.context,
indexX,
indexY,
self.unitWidth,
self.unitHeight,
4,
true,
false
)
Util.text(
self.context,
data.name,
indexX + self.unitPadding,
indexY + self.unitPadding,
'20px',
'#ffffff'
)
// Util.text(self.context, data.title, indexX + self.unitPadding, indexY + self.unitPadding + 30, '20px', '#000000')
const maxWidth = self.unitWidth - 2 * self.unitPadding
Util.wrapText(
self.context,
data.title,
indexX + self.unitPadding,
indexY + self.unitPadding + 24,
maxWidth,
20,
'#000000'
)
})
}
/**
* fill the node outline with colorKey color
*/
drawHiddenCanvas() {
this.hiddenContext.clearRect(-50000, -10000, 100000, 100000)
const self = this
this.virtualContainerNode.selectAll('.orgUnit').each(function () {
const node = self.d3.select(this)
self.hiddenContext.fillStyle = node.attr('colorKey')
Util.roundRect(
self.hiddenContext,
Number(node.attr('x')) - self.unitWidth / 2,
Number(node.attr('y')) - self.unitHeight / 2,
self.unitWidth,
self.unitHeight,
4,
true,
false
)
})
}
setCanvasListener() {
this.setClickListener()
this.setDragListener()
this.setMouseWheelZoomListener()
}
setClickListener() {
const self = this
this.canvasNode.node().addEventListener('click', (e) => {
const colorStr = getColorStrFromCanvas(
self.hiddenContext,
e.layerX,
e.layerY
)
const node = self.colorNodeMap[colorStr]
if (node) {
self.toggleTreeNode(node.data()[0])
self.update(node.data()[0])
}
})
}
setMouseWheelZoomListener() {
const self = this
this.canvasNode.node().addEventListener('mousewheel', (event) => {
event.preventDefault()
if (event.deltaY < 0) {
self.bigger()
} else {
self.smaller()
}
})
}
setDragListener() {
this.onDrag_ = false
this.dragStartPoint_ = { x: 0, y: 0 }
const self = this
this.canvasNode.node().onmousedown = function (e) {
self.dragStartPoint_.x = e.x
self.dragStartPoint_.y = e.y
self.onDrag_ = true
}
this.canvasNode.node().onmousemove = function (e) {
if (!self.onDrag_) {
return
}
self.context.translate(
(e.x - self.dragStartPoint_.x) / self.scale,
(e.y - self.dragStartPoint_.y) / self.scale
)
self.hiddenContext.translate(
(e.x - self.dragStartPoint_.x) / self.scale,
(e.y - self.dragStartPoint_.y) / self.scale
)
self.dragStartPoint_.x = e.x
self.dragStartPoint_.y = e.y
}
this.canvasNode.node().onmouseout = function (e) {
if (self.onDrag_) {
self.onDrag_ = false
}
}
this.canvasNode.node().onmouseup = function (e) {
if (self.onDrag_) {
self.onDrag_ = false
}
}
}
toggleTreeNode(treeNode) {
if (treeNode.children) {
treeNode._children = treeNode.children
treeNode.children = null
} else {
treeNode.children = treeNode._children
treeNode._children = null
}
}
bigger() {
if (this.scale > 7) return
this.clearCanvas_()
this.scale = (this.scale * 5) / 4
this.context.scale(5 / 4, 5 / 4)
this.hiddenContext.scale(5 / 4, 5 / 4)
}
smaller() {
if (this.scale < 0.2) return
this.clearCanvas_()
this.scale = (this.scale * 4) / 5
this.context.scale(4 / 5, 4 / 5)
this.hiddenContext.scale(4 / 5, 4 / 5)
}
clearCanvas_() {
this.context.clearRect(-1000000, -10000, 2000000, 2000000)
this.hiddenContext.clearRect(-1000000, -10000, 2000000, 2000000)
}
}
export default OrgChart
================================================
FILE: packages/tree-chart-demo/src/demo/App.vue
================================================
<template>
<v-app>
<v-toolbar>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title>Tree Chart</v-toolbar-title>
<v-btn
class="menu-item"
:to="Cons.CANVAS_TREE"
@click="to(Cons.CANVAS_TREE)"
text
style="margin-left: 32px;"
:color="selectedMenu === 'canvas' ? 'info' : ''"
>Canvas Chart</v-btn
>
<v-btn
class="menu-item"
:color="selectedMenu === 'svg' ? 'info' : ''"
:to="Cons.SVG_TREE"
@click="to(Cons.SVG_TREE)"
text
normal
>Svg Chart</v-btn
>
<v-spacer></v-spacer>
<v-toolbar-items class="hidden-sm-and-down">
<v-btn flat href="https://github.com/ssthouse">
<v-avatar size="42">
<img
src="https://avatars3.githubusercontent.com/u/10973821?s=460&v=4"
/>
</v-avatar>
<span style="margin-left: 8px;">About me</span>
</v-btn>
<v-btn flat href="https://github.com/ssthouse/organization-chart">
<v-avatar size="42">
<img
src="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
/>
</v-avatar>
Source Code</v-btn
>
</v-toolbar-items>
</v-toolbar>
<router-view style="width: 100%; height: 100%;" />
</v-app>
</template>
<script lang="ts">
import * as Cons from './router/constant'
export default {
name: 'App',
data() {
return {
Cons,
selectedMenu: 'canvas'
}
},
watch: {
$route() {
this.updateSelectedMenu()
}
},
created() {
this.updateSelectedMenu()
},
methods: {
to(routePath){
this.$router.push(routePath);
},
backtoMenu() {
this.$router.push('main')
},
updateSelectedMenu() {
if (this.$route.path === `/${Cons.CANVAS_TREE}`) {
this.selectedMenu = 'canvas'
} else {
this.selectedMenu = 'svg'
}
}
}
}
</script>
<style lang="less" scoped>
.menu-item {
display: inline-block;
display: flex;
height: 100%;
margin: 0;
}
</style>
================================================
FILE: packages/tree-chart-demo/src/demo/google-icon.css
================================================
/* fallback */
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/materialicons/v46/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2) format('woff2');
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmSU5fCRc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmSU5fABc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmSU5fCBc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmSU5fBxc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmSU5fCxc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmSU5fChc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu5mxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu7mxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu4WxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu7WxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fCRc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fABc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fCBc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fBxc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fCxc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fChc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmWUlfCRc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmWUlfABc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmWUlfCBc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmWUlfBxc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmWUlfCxc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmWUlfChc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmWUlfBBc4AMP6lQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
================================================
FILE: packages/tree-chart-demo/src/demo/main.ts
================================================
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
import './google-icon.css'
Vue.use(Vuetify)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
================================================
FILE: packages/tree-chart-demo/src/demo/router/constant.ts
================================================
export const SVG_TREE = 'svgTree'
export const CANVAS_TREE = 'canvasTree'
export const JSON_VIEWER = 'jsonViewer'
================================================
FILE: packages/tree-chart-demo/src/demo/router/index.ts
================================================
import Vue from 'vue'
import Router from 'vue-router'
import CanvasTree from '../../components/CanvasTree.vue'
import VueTree from '../../components/VueTreeDemo.vue'
import * as Cons from './constant'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
redirect: Cons.SVG_TREE
},
{
path: '/' + Cons.CANVAS_TREE,
name: Cons.CANVAS_TREE,
component: CanvasTree
},
{
path: '/' + Cons.SVG_TREE,
name: Cons.SVG_TREE,
component: VueTree
}
]
})
================================================
FILE: packages/tree-chart-demo/src/vue.shims.d.ts
================================================
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
================================================
FILE: packages/tree-chart-demo/template/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>organization-chart</title>
</head>
<body>
<div id="app" style="width: 100%; height: 100%;"></div>
<!-- built files will be auto injected -->
</body>
</html>
================================================
FILE: packages/tree-chart-demo/tsconfig.json
================================================
{
"compilerOptions": {
"outDir": "./build/",
"sourceMap": true,
"strict": false,
"noImplicitReturns": true,
"module": "es2015",
"moduleResolution": "node",
"target": "es5"
},
"include": ["src/**/*"]
}
================================================
FILE: packages/vue-tree-chart/.babelrc
================================================
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"]
}
================================================
FILE: packages/vue-tree-chart/.editorconfig
================================================
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
================================================
FILE: packages/vue-tree-chart/.eslintignore
================================================
/build/
/config/
/dist/
/*.js
library/*.js
src/**/*d.ts
================================================
FILE: packages/vue-tree-chart/.eslintrc.js
================================================
module.exports = {
root: true,
env: {
'node': true
},
extends: [
'plugin:vue/essential',
'@vue/typescript',
'@vue/prettier',
],
parserOptions: {
ecmaVersion: 2020,
},
rules: {
'prettier/prettier': [
'warn',
{
'#': 'prettier config in here :)',
'singleQuote': true,
'semi': false,
'trailingComma': 'none',
'space-before-function-paren': 'off'
}
]
}
}
================================================
FILE: packages/vue-tree-chart/.postcssrc.js
================================================
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
}
}
================================================
FILE: packages/vue-tree-chart/.prettierignore
================================================
/build/
/config/
/dist/
/*.js
library/*.js
================================================
FILE: packages/vue-tree-chart/README.md
================================================
# @ssthouse/vue-tree-chart
## Docs
(https://github.com/ssthouse/vue-tree-chart)[https://github.com/ssthouse/vue-tree-chart]
## 文档
(https://github.com/ssthouse/vue-tree-chart)[https://github.com/ssthouse/vue-tree-chart]
================================================
FILE: packages/vue-tree-chart/build/webpack.config.base.js
================================================
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/demo/main.ts',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.vue$/,
use: ['vue-loader']
},
{
test: /\.ts$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/]
}
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: './template/index.html',
inject: true
})
],
resolve: {
extensions: ['.ts', '.js', '.vue', '.json'],
alias: {
vue$: 'vue/dist/vue.esm.js'
}
}
}
================================================
FILE: packages/vue-tree-chart/build/webpack.config.dev.js
================================================
const merge = require('webpack-merge')
module.exports = merge(require('./webpack.config.base'), {
mode: 'development',
output: {
publicPath: '/'
},
devtool: 'source-map'
})
================================================
FILE: packages/vue-tree-chart/build/webpack.config.library.js
================================================
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
mode: 'development',
entry: './src/vue-tree/index.ts',
output: {
path: path.resolve(__dirname, '..', 'library'),
filename: 'vue-tree-chart.js',
library: 'vue-tree-chart',
libraryTarget: 'umd'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.vue$/,
use: ['vue-loader']
},
{
test: /\.ts$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/\.vue$/]
}
}
]
},
plugins: [new VueLoaderPlugin()],
resolve: {
extensions: ['.ts', '.js', '.vue', '.json'],
alias: {
vue$: 'vue/dist/vue.esm.js'
}
}
}
================================================
FILE: packages/vue-tree-chart/library/.gitkeep
================================================
================================================
FILE: packages/vue-tree-chart/library/vue-tree-chart.js
================================================
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["vue-tree-chart"] = factory();
else
root["vue-tree-chart"] = factory();
})(self, function() {
return /******/ (function() { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./node_modules/@ssthouse/tree-chart-core/build/base/uuid.js":
/*!*******************************************************************!*\
!*** ./node_modules/@ssthouse/tree-chart-core/build/base/uuid.js ***!
\*******************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"uuid\": function() { return /* binding */ uuid; }\n/* harmony export */ });\nfunction uuid() {\n var s = [];\n var hexDigits = '0123456789abcdef';\n for (var i = 0; i < 36; i++) {\n s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);\n }\n s[14] = '4';\n s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);\n s[8] = s[13] = s[18] = s[23] = '-';\n return s.join('');\n}\n\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/@ssthouse/tree-chart-core/build/base/uuid.js?");
/***/ }),
/***/ "./node_modules/@ssthouse/tree-chart-core/build/index.js":
/*!***************************************************************!*\
!*** ./node_modules/@ssthouse/tree-chart-core/build/index.js ***!
\***************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"ANIMATION_DURATION\": function() { return /* reexport safe */ _tree_chart_constant__WEBPACK_IMPORTED_MODULE_1__.ANIMATION_DURATION; },\n/* harmony export */ \"DEFAULT_HEIGHT_DECREMENT\": function() { return /* reexport safe */ _tree_chart_constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_HEIGHT_DECREMENT; },\n/* harmony export */ \"DEFAULT_LEVEL_HEIGHT\": function() { return /* reexport safe */ _tree_chart_constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_LEVEL_HEIGHT; },\n/* harmony export */ \"DEFAULT_NODE_HEIGHT\": function() { return /* reexport safe */ _tree_chart_constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_NODE_HEIGHT; },\n/* harmony export */ \"DEFAULT_NODE_WIDTH\": function() { return /* reexport safe */ _tree_chart_constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_NODE_WIDTH; },\n/* harmony export */ \"MATCH_SCALE_REGEX\": function() { return /* reexport safe */ _tree_chart_constant__WEBPACK_IMPORTED_MODULE_1__.MATCH_SCALE_REGEX; },\n/* harmony export */ \"MATCH_TRANSLATE_REGEX\": function() { return /* reexport safe */ _tree_chart_constant__WEBPACK_IMPORTED_MODULE_1__.MATCH_TRANSLATE_REGEX; },\n/* harmony export */ \"Direction\": function() { return /* reexport safe */ _tree_chart_tree_chart__WEBPACK_IMPORTED_MODULE_2__.Direction; },\n/* harmony export */ \"TreeLinkStyle\": function() { return /* reexport safe */ _tree_chart_tree_chart__WEBPACK_IMPORTED_MODULE_2__.TreeLinkStyle; }\n/* harmony export */ });\n/* harmony import */ var _tree_chart_index__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./tree-chart/index */ \"./node_modules/@ssthouse/tree-chart-core/build/tree-chart/index.js\");\n/* harmony import */ var _tree_chart_constant__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tree-chart/constant */ \"./node_modules/@ssthouse/tree-chart-core/build/tree-chart/constant.js\");\n/* harmony import */ var _tree_chart_tree_chart__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./tree-chart/tree-chart */ \"./node_modules/@ssthouse/tree-chart-core/build/tree-chart/tree-chart.js\");\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (_tree_chart_index__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n\n\n\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/@ssthouse/tree-chart-core/build/index.js?");
/***/ }),
/***/ "./node_modules/@ssthouse/tree-chart-core/build/tree-chart/constant.js":
/*!*****************************************************************************!*\
!*** ./node_modules/@ssthouse/tree-chart-core/build/tree-chart/constant.js ***!
\*****************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"DEFAULT_NODE_WIDTH\": function() { return /* binding */ DEFAULT_NODE_WIDTH; },\n/* harmony export */ \"DEFAULT_NODE_HEIGHT\": function() { return /* binding */ DEFAULT_NODE_HEIGHT; },\n/* harmony export */ \"DEFAULT_LEVEL_HEIGHT\": function() { return /* binding */ DEFAULT_LEVEL_HEIGHT; },\n/* harmony export */ \"DEFAULT_HEIGHT_DECREMENT\": function() { return /* binding */ DEFAULT_HEIGHT_DECREMENT; },\n/* harmony export */ \"ANIMATION_DURATION\": function() { return /* binding */ ANIMATION_DURATION; },\n/* harmony export */ \"MATCH_TRANSLATE_REGEX\": function() { return /* binding */ MATCH_TRANSLATE_REGEX; },\n/* harmony export */ \"MATCH_SCALE_REGEX\": function() { return /* binding */ MATCH_SCALE_REGEX; }\n/* harmony export */ });\nvar DEFAULT_NODE_WIDTH = 100;\nvar DEFAULT_NODE_HEIGHT = 100;\nvar DEFAULT_LEVEL_HEIGHT = 200;\n/**\n * Used to decrement the height of the 'initTransformY' to center diagrams.\n * This is only a hotfix caused by the addition of '__invisible_root' node\n * for multi root purposes.\n */\nvar DEFAULT_HEIGHT_DECREMENT = 200;\nvar ANIMATION_DURATION = 800;\nvar MATCH_TRANSLATE_REGEX = /translate\\((-?\\d+)px, ?(-?\\d+)px\\)/i;\nvar MATCH_SCALE_REGEX = /scale\\((\\S*)\\)/i;\n\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/@ssthouse/tree-chart-core/build/tree-chart/constant.js?");
/***/ }),
/***/ "./node_modules/@ssthouse/tree-chart-core/build/tree-chart/index.js":
/*!**************************************************************************!*\
!*** ./node_modules/@ssthouse/tree-chart-core/build/tree-chart/index.js ***!
\**************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var d3__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! d3 */ \"./node_modules/d3/src/index.js\");\n/* harmony import */ var _constant__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constant */ \"./node_modules/@ssthouse/tree-chart-core/build/tree-chart/constant.js\");\n/* harmony import */ var _tree_chart__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./tree-chart */ \"./node_modules/@ssthouse/tree-chart-core/build/tree-chart/tree-chart.js\");\n/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./util */ \"./node_modules/@ssthouse/tree-chart-core/build/tree-chart/util.js\");\n\n\n\n\nvar TreeChartCore = /** @class */ (function () {\n function TreeChartCore(params) {\n this.treeConfig = {\n nodeWidth: _constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_NODE_WIDTH,\n nodeHeight: _constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_NODE_HEIGHT,\n levelHeight: _constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_LEVEL_HEIGHT,\n };\n this.linkStyle = _tree_chart__WEBPACK_IMPORTED_MODULE_2__.TreeLinkStyle.CURVE;\n this.direction = _tree_chart__WEBPACK_IMPORTED_MODULE_2__.Direction.VERTICAL;\n this.collapseEnabled = true;\n this.currentScale = 1;\n if (params.treeConfig) {\n this.treeConfig = params.treeConfig;\n }\n this.collapseEnabled = params.collapseEnabled;\n this.svgElement = params.svgElement;\n this.domElement = params.domElement;\n this.treeContainer = params.treeContainer;\n this.dataset = this.updatedInternalData(params.dataset);\n if (params.direction)\n this.direction = params.direction;\n if (params.linkStyle)\n this.linkStyle = params.linkStyle;\n }\n TreeChartCore.prototype.init = function () {\n this.draw();\n this.enableDrag();\n this.initTransform();\n };\n TreeChartCore.prototype.getNodeDataList = function () {\n return this.nodeDataList;\n };\n TreeChartCore.prototype.getInitialTransformStyle = function () {\n return {\n transform: \"scale(1) translate(\".concat(this.initTransformX, \"px, \").concat(this.initTransformY, \"px)\"),\n transformOrigin: \"center\",\n };\n };\n TreeChartCore.prototype.zoomIn = function () {\n var originTransformStr = this.domElement.style.transform;\n // 如果已有scale属性, 在原基础上修改\n var targetScale = 1 * 1.2;\n var scaleMatchResult = originTransformStr.match(_constant__WEBPACK_IMPORTED_MODULE_1__.MATCH_SCALE_REGEX);\n if (scaleMatchResult && scaleMatchResult.length > 0) {\n var originScale = parseFloat(scaleMatchResult[1]);\n targetScale *= originScale;\n }\n this.setScale(targetScale);\n };\n TreeChartCore.prototype.zoomOut = function () {\n var originTransformStr = this.domElement.style.transform;\n // 如果已有scale属性, 在原基础上修改\n var targetScale = 1 / 1.2;\n var scaleMatchResult = originTransformStr.match(_constant__WEBPACK_IMPORTED_MODULE_1__.MATCH_SCALE_REGEX);\n if (scaleMatchResult && scaleMatchResult.length > 0) {\n var originScale = parseFloat(scaleMatchResult[1]);\n targetScale = originScale / 1.2;\n }\n this.setScale(targetScale);\n };\n TreeChartCore.prototype.restoreScale = function () {\n this.setScale(1);\n };\n TreeChartCore.prototype.setScale = function (scaleNum) {\n if (typeof scaleNum !== \"number\")\n return;\n var pos = this.getTranslate();\n var translateString = \"translate(\".concat(pos[0], \"px, \").concat(pos[1], \"px)\");\n this.svgElement.style.transform = \"scale(\".concat(scaleNum, \") \") + translateString;\n this.domElement.style.transform =\n \"scale(\".concat(scaleNum, \") \") + translateString;\n this.currentScale = scaleNum;\n };\n TreeChartCore.prototype.getTranslate = function () {\n var string = this.svgElement.style.transform;\n var match = string.match(_constant__WEBPACK_IMPORTED_MODULE_1__.MATCH_TRANSLATE_REGEX);\n if (match === null) {\n return [null, null];\n }\n var x = parseInt(match[1]);\n var y = parseInt(match[2]);\n return [x, y];\n };\n TreeChartCore.prototype.isVertical = function () {\n return this.direction === _tree_chart__WEBPACK_IMPORTED_MODULE_2__.Direction.VERTICAL;\n };\n /**\n * 根据link数据,生成svg path data\n */\n TreeChartCore.prototype.generateLinkPath = function (d) {\n var self = this;\n if (this.linkStyle === _tree_chart__WEBPACK_IMPORTED_MODULE_2__.TreeLinkStyle.CURVE) {\n return this.generateCurceLinkPath(self, d);\n }\n if (this.linkStyle === _tree_chart__WEBPACK_IMPORTED_MODULE_2__.TreeLinkStyle.STRAIGHT) {\n // the link path is: source -> secondPoint -> thirdPoint -> target\n return this.generateStraightLinkPath(d);\n }\n };\n TreeChartCore.prototype.generateCurceLinkPath = function (self, d) {\n var linkPath = this.isVertical()\n ? d3__WEBPACK_IMPORTED_MODULE_0__.linkVertical()\n : d3__WEBPACK_IMPORTED_MODULE_0__.linkHorizontal();\n linkPath\n .x(function (d) {\n return d.x;\n })\n .y(function (d) {\n return d.y;\n })\n .source(function (d) {\n var sourcePoint = {\n x: d.source.x,\n y: d.source.y,\n };\n return self.direction === _tree_chart__WEBPACK_IMPORTED_MODULE_2__.Direction.VERTICAL\n ? sourcePoint\n : (0,_util__WEBPACK_IMPORTED_MODULE_3__.rotatePoint)(sourcePoint);\n })\n .target(function (d) {\n var targetPoint = {\n x: d.target.x,\n y: d.target.y,\n };\n return self.direction === _tree_chart__WEBPACK_IMPORTED_MODULE_2__.Direction.VERTICAL\n ? targetPoint\n : (0,_util__WEBPACK_IMPORTED_MODULE_3__.rotatePoint)(targetPoint);\n });\n return linkPath(d);\n };\n TreeChartCore.prototype.generateStraightLinkPath = function (d) {\n var linkPath = d3__WEBPACK_IMPORTED_MODULE_0__.path();\n var sourcePoint = { x: d.source.x, y: d.source.y };\n var targetPoint = { x: d.target.x, y: d.target.y };\n if (!this.isVertical()) {\n sourcePoint = (0,_util__WEBPACK_IMPORTED_MODULE_3__.rotatePoint)(sourcePoint);\n targetPoint = (0,_util__WEBPACK_IMPORTED_MODULE_3__.rotatePoint)(targetPoint);\n }\n var xOffset = targetPoint.x - sourcePoint.x;\n var yOffset = targetPoint.y - sourcePoint.y;\n var secondPoint = this.isVertical()\n ? { x: sourcePoint.x, y: sourcePoint.y + yOffset / 2 }\n : { x: sourcePoint.x + xOffset / 2, y: sourcePoint.y };\n var thirdPoint = this.isVertical()\n ? { x: targetPoint.x, y: sourcePoint.y + yOffset / 2 }\n : { x: sourcePoint.x + xOffset / 2, y: targetPoint.y };\n linkPath.moveTo(sourcePoint.x, sourcePoint.y);\n linkPath.lineTo(secondPoint.x, secondPoint.y);\n linkPath.lineTo(thirdPoint.x, thirdPoint.y);\n linkPath.lineTo(targetPoint.x, targetPoint.y);\n return linkPath.toString();\n };\n TreeChartCore.prototype.updateDataList = function () {\n var _a = this.buildTree(), nodeDataList = _a[0], linkDataList = _a[1];\n nodeDataList.splice(0, 1);\n linkDataList = linkDataList.filter(function (x) { return x.source.data.name !== \"__invisible_root\"; });\n this.linkDataList = linkDataList;\n this.nodeDataList = nodeDataList;\n };\n TreeChartCore.prototype.draw = function () {\n this.updateDataList();\n var identifier = this.dataset[\"identifier\"];\n var specialLinks = this.dataset[\"links\"];\n if (specialLinks && identifier) {\n var _loop_1 = function (link) {\n var parent_1 = void 0, children = undefined;\n if (identifier === \"value\") {\n parent_1 = this_1.nodeDataList.find(function (d) {\n return d[identifier] == link.parent;\n });\n children = this_1.nodeDataList.filter(function (d) {\n return d[identifier] == link.child;\n });\n }\n else {\n parent_1 = this_1.nodeDataList.find(function (d) {\n return d[\"data\"][identifier] == link.parent;\n });\n children = this_1.nodeDataList.filter(function (d) {\n return d[\"data\"][identifier] == link.child;\n });\n }\n if (parent_1 && children) {\n for (var _a = 0, children_1 = children; _a < children_1.length; _a++) {\n var child = children_1[_a];\n var new_link = {\n source: parent_1,\n target: child,\n };\n this_1.linkDataList.push(new_link);\n }\n }\n };\n var this_1 = this;\n for (var _i = 0, specialLinks_1 = specialLinks; _i < specialLinks_1.length; _i++) {\n var link = specialLinks_1[_i];\n _loop_1(link);\n }\n }\n this.svgSelection = d3__WEBPACK_IMPORTED_MODULE_0__.select(this.svgElement);\n var self = this;\n var links = this.svgSelection\n .selectAll(\".link\")\n .data(this.linkDataList, function (d) {\n return \"\".concat(d.source.data._key, \"-\").concat(d.target.data._key);\n });\n links\n .enter()\n .append(\"path\")\n .style(\"opacity\", 0)\n .transition()\n .duration(_constant__WEBPACK_IMPORTED_MODULE_1__.ANIMATION_DURATION)\n .ease(d3__WEBPACK_IMPORTED_MODULE_0__.easeCubicInOut)\n .style(\"opacity\", 1)\n .attr(\"class\", \"link\")\n .attr(\"d\", function (d) {\n return self.generateLinkPath(d);\n });\n links\n .transition()\n .duration(_constant__WEBPACK_IMPORTED_MODULE_1__.ANIMATION_DURATION)\n .ease(d3__WEBPACK_IMPORTED_MODULE_0__.easeCubicInOut)\n .attr(\"d\", function (d) {\n return self.generateLinkPath(d);\n });\n links\n .exit()\n .transition()\n .duration(_constant__WEBPACK_IMPORTED_MODULE_1__.ANIMATION_DURATION / 2)\n .ease(d3__WEBPACK_IMPORTED_MODULE_0__.easeCubicInOut)\n .style(\"opacity\", 0)\n .remove();\n };\n /**\n * Returns updated dataset by deep copying every nodes from the externalData and adding unique '_key' attributes.\n **/\n TreeChartCore.prototype.updatedInternalData = function (externalData) {\n var data = { name: \"__invisible_root\", children: [] };\n if (!externalData)\n return data;\n if (Array.isArray(externalData)) {\n for (var i = externalData.length - 1; i >= 0; i--) {\n data.children.push((0,_util__WEBPACK_IMPORTED_MODULE_3__.deepCopy)(externalData[i]));\n }\n }\n else {\n data.children.push((0,_util__WEBPACK_IMPORTED_MODULE_3__.deepCopy)(externalData));\n }\n return data;\n };\n TreeChartCore.prototype.buildTree = function () {\n var treeBuilder = d3__WEBPACK_IMPORTED_MODULE_0__.tree()\n .nodeSize([this.treeConfig.nodeWidth, this.treeConfig.levelHeight]);\n var tree = treeBuilder(d3__WEBPACK_IMPORTED_MODULE_0__.hierarchy(this.dataset));\n return [tree.descendants(), tree.links()];\n };\n TreeChartCore.prototype.enableDrag = function () {\n var _this = this;\n var startX = 0;\n var startY = 0;\n var isDrag = false;\n // 保存鼠标点下时的位移\n var mouseDownTransform = \"\";\n this.treeContainer.onmousedown = function (event) {\n mouseDownTransform = _this.svgElement.style.transform;\n startX = event.clientX;\n startY = event.clientY;\n isDrag = true;\n };\n this.treeContainer.onmousemove = function (event) {\n if (!isDrag)\n return;\n var originTransform = mouseDownTransform;\n var originOffsetX = 0;\n var originOffsetY = 0;\n if (originTransform) {\n var result = originTransform.match(_constant__WEBPACK_IMPORTED_MODULE_1__.MATCH_TRANSLATE_REGEX);\n if (result !== null && result.length !== 0) {\n var _a = result.slice(1), offsetX = _a[0], offsetY = _a[1];\n originOffsetX = parseInt(offsetX);\n originOffsetY = parseInt(offsetY);\n }\n }\n var newX = Math.floor((event.clientX - startX) / _this.currentScale) +\n originOffsetX;\n var newY = Math.floor((event.clientY - startY) / _this.currentScale) +\n originOffsetY;\n var transformStr = \"translate(\".concat(newX, \"px, \").concat(newY, \"px)\");\n if (originTransform) {\n transformStr = originTransform.replace(_constant__WEBPACK_IMPORTED_MODULE_1__.MATCH_TRANSLATE_REGEX, transformStr);\n }\n _this.svgElement.style.transform = transformStr;\n _this.domElement.style.transform = transformStr;\n };\n this.treeContainer.onmouseup = function () {\n startX = 0;\n startY = 0;\n isDrag = false;\n };\n };\n TreeChartCore.prototype.initTransform = function () {\n var containerWidth = this.domElement.offsetWidth;\n var containerHeight = this.domElement.offsetHeight;\n if (this.isVertical()) {\n this.initTransformX = Math.floor(containerWidth / 2);\n this.initTransformY = Math.floor(this.treeConfig.nodeHeight - _constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_HEIGHT_DECREMENT);\n }\n else {\n this.initTransformX = Math.floor(this.treeConfig.nodeWidth - _constant__WEBPACK_IMPORTED_MODULE_1__.DEFAULT_HEIGHT_DECREMENT);\n this.initTransformY = Math.floor(containerHeight / 2);\n }\n };\n TreeChartCore.prototype.onClickNode = function (index) {\n if (this.collapseEnabled) {\n var curNode = this.nodeDataList[index];\n if (curNode.data.children) {\n curNode.data._children = curNode.data.children;\n curNode.data.children = null;\n curNode.data._collapsed = true;\n }\n else {\n curNode.data.children = curNode.data._children;\n curNode.data._children = null;\n curNode.data._collapsed = false;\n }\n this.draw();\n }\n };\n /**\n * call this function to update dataset\n * notice : you need to update the view rendered by `nodeDataList` too\n * @param dataset the new dataset to show in chart\n */\n TreeChartCore.prototype.updateDataset = function (dataset) {\n this.dataset = this.updatedInternalData(dataset);\n this.draw();\n };\n /**\n * release all dom reference\n */\n TreeChartCore.prototype.destroy = function () {\n this.svgElement = null;\n this.domElement = null;\n this.treeContainer = null;\n };\n return TreeChartCore;\n}());\n/* harmony default export */ __webpack_exports__[\"default\"] = (TreeChartCore);\n\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/@ssthouse/tree-chart-core/build/tree-chart/index.js?");
/***/ }),
/***/ "./node_modules/@ssthouse/tree-chart-core/build/tree-chart/tree-chart.js":
/*!*******************************************************************************!*\
!*** ./node_modules/@ssthouse/tree-chart-core/build/tree-chart/tree-chart.js ***!
\*******************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Direction\": function() { return /* binding */ Direction; },\n/* harmony export */ \"TreeLinkStyle\": function() { return /* binding */ TreeLinkStyle; }\n/* harmony export */ });\nvar Direction;\n(function (Direction) {\n Direction[\"VERTICAL\"] = \"vertical\";\n Direction[\"HORIZONTAL\"] = \"horizontal\";\n})(Direction || (Direction = {}));\nvar TreeLinkStyle;\n(function (TreeLinkStyle) {\n TreeLinkStyle[\"CURVE\"] = \"curve\";\n TreeLinkStyle[\"STRAIGHT\"] = \"straight\";\n})(TreeLinkStyle || (TreeLinkStyle = {}));\n\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/@ssthouse/tree-chart-core/build/tree-chart/tree-chart.js?");
/***/ }),
/***/ "./node_modules/@ssthouse/tree-chart-core/build/tree-chart/util.js":
/*!*************************************************************************!*\
!*** ./node_modules/@ssthouse/tree-chart-core/build/tree-chart/util.js ***!
\*************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"rotatePoint\": function() { return /* binding */ rotatePoint; },\n/* harmony export */ \"deepCopy\": function() { return /* binding */ deepCopy; }\n/* harmony export */ });\n/* harmony import */ var _base_uuid__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../base/uuid */ \"./node_modules/@ssthouse/tree-chart-core/build/base/uuid.js\");\n\nfunction rotatePoint(_a) {\n var x = _a.x, y = _a.y;\n return {\n x: y,\n y: x,\n };\n}\n/**\n* Returns a deep copy of selected node (copy of itself and it's children).\n* If selected node or it's children have no '_key' attribute it will assign a new one.\n**/\nfunction deepCopy(node) {\n var obj = { _key: (0,_base_uuid__WEBPACK_IMPORTED_MODULE_0__.uuid)() };\n for (var key in node) {\n if (node[key] === null) {\n obj[key] = null;\n }\n else if (Array.isArray(node[key])) {\n obj[key] = node[key].map(function (x) { return deepCopy(x); });\n }\n else if (typeof node[key] === \"object\") {\n obj[key] = deepCopy(node[key]);\n }\n else {\n obj[key] = node[key];\n }\n }\n return obj;\n}\n\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/@ssthouse/tree-chart-core/build/tree-chart/util.js?");
/***/ }),
/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less&":
/*!*********************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less& ***!
\*********************************************************************************************************************************************************************************************************************************************************************/
/***/ (function(module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".tree-container .node {\\n fill: grey !important;\\n}\\n.tree-container .link {\\n stroke-width: 2px !important;\\n fill: transparent !important;\\n stroke: #cecece !important;\\n}\\n\", \"\"]);\n// Exports\n/* harmony default export */ __webpack_exports__[\"default\"] = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options");
/***/ }),
/***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true&":
/*!*********************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true& ***!
\*********************************************************************************************************************************************************************************************************************************************************************************************/
/***/ (function(module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".tree-node-item-enter[data-v-56c15873],\\n.tree-node-item-leave-to[data-v-56c15873] {\\n transition-timing-function: ease-in-out;\\n transition: transform 0.8s;\\n opacity: 0;\\n}\\n.tree-node-item-enter-active[data-v-56c15873],\\n.tree-node-item-leave-active[data-v-56c15873] {\\n transition-timing-function: ease-in-out;\\n transition: all 0.8s;\\n}\\n.tree-container[data-v-56c15873] {\\n position: relative;\\n overflow: hidden;\\n}\\n.tree-container .vue-tree[data-v-56c15873] {\\n position: relative;\\n}\\n.tree-container > svg[data-v-56c15873],\\n.tree-container .dom-container[data-v-56c15873] {\\n width: 100%;\\n height: 100%;\\n position: absolute;\\n left: 0;\\n top: 0;\\n overflow: visible;\\n transform-origin: 0 50%;\\n}\\n.tree-container .dom-container[data-v-56c15873] {\\n z-index: 1;\\n pointer-events: none;\\n}\\n.node-slot[data-v-56c15873] {\\n cursor: pointer;\\n pointer-events: all;\\n position: absolute;\\n background-color: transparent;\\n box-sizing: border-box;\\n transform: translate(-50%, -50%);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-sizing: content-box;\\n transition: all 0.8s;\\n transition-timing-function: ease-in-out;\\n}\\n\", \"\"]);\n// Exports\n/* harmony default export */ __webpack_exports__[\"default\"] = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options");
/***/ }),
/***/ "./node_modules/css-loader/dist/runtime/api.js":
/*!*****************************************************!*\
!*** ./node_modules/css-loader/dist/runtime/api.js ***!
\*****************************************************/
/***/ (function(module) {
eval("\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = []; // return the list of modules as css string\n\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n\n content += cssWithMappingToString(item);\n\n if (needLayer) {\n content += \"}\";\n }\n\n if (item[2]) {\n content += \"}\";\n }\n\n if (item[4]) {\n content += \"}\";\n }\n\n return content;\n }).join(\"\");\n }; // import a list of modules into the list\n\n\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n\n var alreadyImportedModules = {};\n\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n\n list.push(item);\n }\n };\n\n return list;\n};\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/css-loader/dist/runtime/api.js?");
/***/ }),
/***/ "./node_modules/css-loader/dist/runtime/noSourceMaps.js":
/*!**************************************************************!*\
!*** ./node_modules/css-loader/dist/runtime/noSourceMaps.js ***!
\**************************************************************/
/***/ (function(module) {
eval("\n\nmodule.exports = function (i) {\n return i[1];\n};\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/css-loader/dist/runtime/noSourceMaps.js?");
/***/ }),
/***/ "./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less&":
/*!*************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less& ***!
\*************************************************************************************************************************************************************************************************************************************************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/less-loader/dist/cjs.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./VueTree.vue?vue&type=style&index=0&lang=less& */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less&\");\n\n \n \n \n \n \n \n \n \n \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n /* harmony default export */ __webpack_exports__[\"default\"] = (_node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options");
/***/ }),
/***/ "./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true&":
/*!*************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true& ***!
\*************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleDomAPI.js */ \"./node_modules/style-loader/dist/runtime/styleDomAPI.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertBySelector.js */ \"./node_modules/style-loader/dist/runtime/insertBySelector.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js */ \"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/insertStyleElement.js */ \"./node_modules/style-loader/dist/runtime/insertStyleElement.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! !../../node_modules/style-loader/dist/runtime/styleTagTransform.js */ \"./node_modules/style-loader/dist/runtime/styleTagTransform.js\");\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_1_id_56c15873_lang_less_scoped_true___WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/less-loader/dist/cjs.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true& */ \"./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true&\");\n\n \n \n \n \n \n \n \n \n \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_1_id_56c15873_lang_less_scoped_true___WEBPACK_IMPORTED_MODULE_6__[\"default\"], options);\n\n\n\n\n /* harmony default export */ __webpack_exports__[\"default\"] = (_node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_1_id_56c15873_lang_less_scoped_true___WEBPACK_IMPORTED_MODULE_6__[\"default\"] && _node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_1_id_56c15873_lang_less_scoped_true___WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals ? _node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_1_id_56c15873_lang_less_scoped_true___WEBPACK_IMPORTED_MODULE_6__[\"default\"].locals : undefined);\n\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options");
/***/ }),
/***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js":
/*!****************************************************************************!*\
!*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***!
\****************************************************************************/
/***/ (function(module) {
eval("\n\nvar stylesInDOM = [];\n\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n\n return result;\n}\n\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n\n identifiers.push(identifier);\n }\n\n return identifiers;\n}\n\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n\n return updater;\n}\n\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n\n var newLastIdentifiers = modulesToDom(newList, options);\n\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n\n var _index = getIndexByIdentifier(_identifier);\n\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n\n stylesInDOM.splice(_index, 1);\n }\n }\n\n lastIdentifiers = newLastIdentifiers;\n };\n};\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js?");
/***/ }),
/***/ "./node_modules/style-loader/dist/runtime/insertBySelector.js":
/*!********************************************************************!*\
!*** ./node_modules/style-loader/dist/runtime/insertBySelector.js ***!
\********************************************************************/
/***/ (function(module) {
eval("\n\nvar memo = {};\n/* istanbul ignore next */\n\nfunction getTarget(target) {\n if (typeof memo[target] === \"undefined\") {\n var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself\n\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n\n memo[target] = styleTarget;\n }\n\n return memo[target];\n}\n/* istanbul ignore next */\n\n\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n\n target.appendChild(style);\n}\n\nmodule.exports = insertBySelector;\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/style-loader/dist/runtime/insertBySelector.js?");
/***/ }),
/***/ "./node_modules/style-loader/dist/runtime/insertStyleElement.js":
/*!**********************************************************************!*\
!*** ./node_modules/style-loader/dist/runtime/insertStyleElement.js ***!
\**********************************************************************/
/***/ (function(module) {
eval("\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement(\"style\");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\n\nmodule.exports = insertStyleElement;\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/style-loader/dist/runtime/insertStyleElement.js?");
/***/ }),
/***/ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js":
/*!**********************************************************************************!*\
!*** ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js ***!
\**********************************************************************************/
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
eval("\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = true ? __webpack_require__.nc : 0;\n\n if (nonce) {\n styleElement.setAttribute(\"nonce\", nonce);\n }\n}\n\nmodule.exports = setAttributesWithoutAttributes;\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js?");
/***/ }),
/***/ "./node_modules/style-loader/dist/runtime/styleDomAPI.js":
/*!***************************************************************!*\
!*** ./node_modules/style-loader/dist/runtime/styleDomAPI.js ***!
\***************************************************************/
/***/ (function(module) {
eval("\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = \"\";\n\n if (obj.supports) {\n css += \"@supports (\".concat(obj.supports, \") {\");\n }\n\n if (obj.media) {\n css += \"@media \".concat(obj.media, \" {\");\n }\n\n var needLayer = typeof obj.layer !== \"undefined\";\n\n if (needLayer) {\n css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\n }\n\n css += obj.css;\n\n if (needLayer) {\n css += \"}\";\n }\n\n if (obj.media) {\n css += \"}\";\n }\n\n if (obj.supports) {\n css += \"}\";\n }\n\n var sourceMap = obj.sourceMap;\n\n if (sourceMap && typeof btoa !== \"undefined\") {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n } // For old IE\n\n /* istanbul ignore if */\n\n\n options.styleTagTransform(css, styleElement, options.options);\n}\n\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n\n styleElement.parentNode.removeChild(styleElement);\n}\n/* istanbul ignore next */\n\n\nfunction domAPI(options) {\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\n\nmodule.exports = domAPI;\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/style-loader/dist/runtime/styleDomAPI.js?");
/***/ }),
/***/ "./node_modules/style-loader/dist/runtime/styleTagTransform.js":
/*!*********************************************************************!*\
!*** ./node_modules/style-loader/dist/runtime/styleTagTransform.js ***!
\*********************************************************************/
/***/ (function(module) {
eval("\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n\n styleElement.appendChild(document.createTextNode(css));\n }\n}\n\nmodule.exports = styleTagTransform;\n\n//# sourceURL=webpack://vue-tree-chart/./node_modules/style-loader/dist/runtime/styleTagTransform.js?");
/***/ }),
/***/ "./src/vue-tree/index.ts":
/*!*******************************!*\
!*** ./src/vue-tree/index.ts ***!
\*******************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _VueTree_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./VueTree.vue */ \"./src/vue-tree/VueTree.vue\");\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (_VueTree_vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/index.ts?");
/***/ }),
/***/ "./src/vue-tree/VueTree.vue":
/*!**********************************!*\
!*** ./src/vue-tree/VueTree.vue ***!
\**********************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _VueTree_vue_vue_type_template_id_56c15873_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./VueTree.vue?vue&type=template&id=56c15873&scoped=true& */ \"./src/vue-tree/VueTree.vue?vue&type=template&id=56c15873&scoped=true&\");\n/* harmony import */ var _VueTree_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./VueTree.vue?vue&type=script&lang=js& */ \"./src/vue-tree/VueTree.vue?vue&type=script&lang=js&\");\n/* harmony import */ var _VueTree_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./VueTree.vue?vue&type=style&index=0&lang=less& */ \"./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less&\");\n/* harmony import */ var _VueTree_vue_vue_type_style_index_1_id_56c15873_lang_less_scoped_true___WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true& */ \"./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true&\");\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! !../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n;\n\n\n\n/* normalize component */\n\nvar component = (0,_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\n _VueTree_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _VueTree_vue_vue_type_template_id_56c15873_scoped_true___WEBPACK_IMPORTED_MODULE_0__.render,\n _VueTree_vue_vue_type_template_id_56c15873_scoped_true___WEBPACK_IMPORTED_MODULE_0__.staticRenderFns,\n false,\n null,\n \"56c15873\",\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"src/vue-tree/VueTree.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?");
/***/ }),
/***/ "./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=script&lang=js&":
/*!**********************************************************************************************************************!*\
!*** ./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=script&lang=js& ***!
\**********************************************************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ssthouse_tree_chart_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ssthouse/tree-chart-core */ \"./node_modules/@ssthouse/tree-chart-core/build/index.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst formatDimension = (dimension) => {\n if (typeof dimension === \"number\") return `${dimension}px`;\n if (dimension.indexOf(\"px\") !== -1) {\n return dimension;\n } else {\n return `${dimension}px`;\n }\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"vue-tree\",\n props: {\n config: {\n type: Object,\n default: () => {\n return {\n nodeWidth: _ssthouse_tree_chart_core__WEBPACK_IMPORTED_MODULE_0__.DEFAULT_NODE_WIDTH,\n nodeHeight: _ssthouse_tree_chart_core__WEBPACK_IMPORTED_MODULE_0__.DEFAULT_NODE_HEIGHT,\n levelHeight: _ssthouse_tree_chart_core__WEBPACK_IMPORTED_MODULE_0__.DEFAULT_LEVEL_HEIGHT,\n };\n },\n },\n linkStyle: {\n type: String,\n default: _ssthouse_tree_chart_core__WEBPACK_IMPORTED_MODULE_0__.TreeLinkStyle.CURVE,\n },\n direction: {\n type: String,\n default: _ssthouse_tree_chart_core__WEBPACK_IMPORTED_MODULE_0__.Direction.VERTICAL,\n },\n collapseEnabled: {\n type: Boolean,\n default: true,\n },\n // 展示的层级数据, 样例数据如: hierachical.json\n dataset: {\n type: [Object, Array],\n required: true,\n },\n },\n data() {\n return {\n formatDimension,\n Direction: _ssthouse_tree_chart_core__WEBPACK_IMPORTED_MODULE_0__.Direction,\n treeChartCore: null,\n nodeDataList: [],\n initialTransformStyle: {},\n };\n },\n mounted() {\n this.init();\n },\n beforeUnmount() {\n // remove dom reference\n this.treeChartCore.destroy();\n },\n methods: {\n init() {\n this.treeChartCore = new _ssthouse_tree_chart_core__WEBPACK_IMPORTED_MODULE_0__[\"default\"]({\n svgElement: this.$refs.svg,\n domElement: this.$refs.domContainer,\n treeContainer: this.$refs.container,\n dataset: this.dataset,\n direction: this.direction,\n treeConfig: this.config,\n collapseEnabled: this.collapseEnabled,\n linkStyle: this.linkStyle,\n });\n this.treeChartCore.init();\n this.nodeDataList = this.treeChartCore.getNodeDataList();\n this.initialTransformStyle =\n this.treeChartCore.getInitialTransformStyle();\n },\n zoomIn() {\n this.treeChartCore.zoomIn();\n },\n zoomOut() {\n this.treeChartCore.zoomOut();\n },\n restoreScale() {\n this.treeChartCore.setScale(1);\n },\n onClickNode(index) {\n this.treeChartCore.onClickNode(index);\n this.nodeDataList = this.treeChartCore.getNodeDataList();\n },\n },\n watch: {\n dataset: {\n deep: true,\n handler: function () {\n this.treeChartCore.updateDataset(this.dataset);\n this.nodeDataList = this.treeChartCore.getNodeDataList();\n },\n },\n },\n});\n\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?./node_modules/vue-loader/lib/index.js??vue-loader-options");
/***/ }),
/***/ "./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less&":
/*!********************************************************************!*\
!*** ./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less& ***!
\********************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_style_loader_dist_cjs_js_node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/style-loader/dist/cjs.js!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/less-loader/dist/cjs.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./VueTree.vue?vue&type=style&index=0&lang=less& */ \"./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=0&lang=less&\");\n\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?");
/***/ }),
/***/ "./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true&":
/*!********************************************************************************************!*\
!*** ./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true& ***!
\********************************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_style_loader_dist_cjs_js_node_modules_css_loader_dist_cjs_js_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_less_loader_dist_cjs_js_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_style_index_1_id_56c15873_lang_less_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/style-loader/dist/cjs.js!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/less-loader/dist/cjs.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true& */ \"./node_modules/style-loader/dist/cjs.js!./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/less-loader/dist/cjs.js!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=style&index=1&id=56c15873&lang=less&scoped=true&\");\n\n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?");
/***/ }),
/***/ "./src/vue-tree/VueTree.vue?vue&type=script&lang=js&":
/*!***********************************************************!*\
!*** ./src/vue-tree/VueTree.vue?vue&type=script&lang=js& ***!
\***********************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./VueTree.vue?vue&type=script&lang=js& */ \"./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=script&lang=js&\");\n /* harmony default export */ __webpack_exports__[\"default\"] = (_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[\"default\"]); \n\n//# sourceURL=webpack://vue-tree-chart/./src/vue-tree/VueTree.vue?");
/***/ }),
/***/ "./src/vue-tree/VueTree.vue?vue&type=template&id=56c15873&scoped=true&":
/*!*****************************************************************************!*\
!*** ./src/vue-tree/VueTree.vue?vue&type=template&id=56c15873&scoped=true& ***!
\*****************************************************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"render\": function() { return /* reexport safe */ _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_template_id_56c15873_scoped_true___WEBPACK_IMPORTED_MODULE_0__.render; },\n/* harmony export */ \"staticRenderFns\": function() { return /* reexport safe */ _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_template_id_56c15873_scoped_true___WEBPACK_IMPORTED_MODULE_0__.staticRenderFns; }\n/* harmony export */ });\n/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_VueTree_vue_vue_type_template_id_56c15873_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./VueTree.vue?vue&type=template&id=56c15873&scoped=true& */ \"./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib/index.js??vue-loader-options!./src/vue-tree/VueTree.vue?vue&type=template&id=56c15873&scoped=true&\");\n\n\n/
gitextract_r67z_mc_/
├── .github/
│ └── workflows/
│ ├── build.yml
│ ├── deploy.yml
│ └── release.yml
├── .gitignore
├── .npmrc
├── LICENSE.md
├── README-CN.md
├── README.md
├── docs/
│ ├── canvas-tree-chart-CN.md
│ ├── canvas-tree-chart.md
│ ├── react-tree-chart.md
│ ├── tech-underneath.md
│ ├── vue-tree-chart-CN.md
│ └── vue-tree-chart.md
├── lerna.json
├── package.json
├── packages/
│ ├── react-tree-chart/
│ │ ├── .babelrc
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── public/
│ │ │ ├── index.html
│ │ │ ├── manifest.json
│ │ │ └── robots.txt
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── demo/
│ │ │ │ ├── App.css
│ │ │ │ ├── App.tsx
│ │ │ │ ├── index.css
│ │ │ │ └── react-app-env.d.ts
│ │ │ ├── index.css
│ │ │ ├── index.tsx
│ │ │ ├── react-app-env.d.ts
│ │ │ ├── setupTests.ts
│ │ │ └── tree-chart/
│ │ │ ├── react-tree-chart.scss
│ │ │ ├── react-tree-chart.tsx
│ │ │ └── typings.d.ts
│ │ └── tsconfig.json
│ ├── tree-chart-core/
│ │ ├── .eslintrc.js
│ │ ├── .gitignore
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── base/
│ │ │ │ └── uuid.ts
│ │ │ ├── index.ts
│ │ │ └── tree-chart/
│ │ │ ├── constant.ts
│ │ │ ├── index.ts
│ │ │ ├── tree-chart.ts
│ │ │ └── util.ts
│ │ └── tsconfig.json
│ ├── tree-chart-demo/
│ │ ├── build/
│ │ │ ├── webpack.config.base.js
│ │ │ ├── webpack.config.dev.js
│ │ │ └── webpack.config.prod.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── base/
│ │ │ │ ├── color-util.ts
│ │ │ │ ├── data-generator.ts
│ │ │ │ ├── utils.ts
│ │ │ │ └── uuid.ts
│ │ │ ├── components/
│ │ │ │ ├── CanvasTree.vue
│ │ │ │ ├── VueTreeDemo.vue
│ │ │ │ └── org-chart.ts
│ │ │ ├── demo/
│ │ │ │ ├── App.vue
│ │ │ │ ├── google-icon.css
│ │ │ │ ├── main.ts
│ │ │ │ └── router/
│ │ │ │ ├── constant.ts
│ │ │ │ └── index.ts
│ │ │ └── vue.shims.d.ts
│ │ ├── template/
│ │ │ └── index.html
│ │ └── tsconfig.json
│ ├── vue-tree-chart/
│ │ ├── .babelrc
│ │ ├── .editorconfig
│ │ ├── .eslintignore
│ │ ├── .eslintrc.js
│ │ ├── .postcssrc.js
│ │ ├── .prettierignore
│ │ ├── README.md
│ │ ├── build/
│ │ │ ├── webpack.config.base.js
│ │ │ ├── webpack.config.dev.js
│ │ │ └── webpack.config.library.js
│ │ ├── library/
│ │ │ ├── .gitkeep
│ │ │ └── vue-tree-chart.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── base/
│ │ │ │ └── uuid.ts
│ │ │ ├── demo/
│ │ │ │ ├── App.vue
│ │ │ │ └── main.ts
│ │ │ ├── vue-tree/
│ │ │ │ ├── VueTree.vue
│ │ │ │ └── index.ts
│ │ │ └── vue.shims.d.ts
│ │ ├── template/
│ │ │ └── index.html
│ │ └── tsconfig.json
│ └── vue3-tree-chart/
│ ├── .gitignore
│ ├── README.md
│ ├── babel.config.js
│ ├── package.json
│ ├── public/
│ │ └── index.html
│ ├── src/
│ │ ├── App.vue
│ │ ├── base/
│ │ │ └── uuid.js
│ │ ├── components/
│ │ │ └── HelloWorld.vue
│ │ ├── main.js
│ │ └── vue-tree/
│ │ ├── VueTree.vue
│ │ └── index.js
│ └── vite.config.js
└── scripts/
└── publish-safe.sh
SYMBOL INDEX (87 symbols across 16 files)
FILE: packages/react-tree-chart/src/demo/App.tsx
function App (line 5) | function App() {
FILE: packages/react-tree-chart/src/tree-chart/react-tree-chart.tsx
type TreeChartNodeProps (line 15) | interface TreeChartNodeProps {
type TreeChartConfig (line 20) | interface TreeChartConfig {
type TreeChartProps (line 26) | interface TreeChartProps {
constant DEFAULT_CONFIG (line 45) | const DEFAULT_CONFIG = {
method zoomIn (line 112) | zoomIn() {
method zoomOut (line 115) | zoomOut() {
method restoreScale (line 118) | restoreScale() {
FILE: packages/tree-chart-core/src/base/uuid.ts
function uuid (line 2) | function uuid(): string {
FILE: packages/tree-chart-core/src/tree-chart/constant.ts
constant DEFAULT_NODE_WIDTH (line 1) | const DEFAULT_NODE_WIDTH = 100;
constant DEFAULT_NODE_HEIGHT (line 2) | const DEFAULT_NODE_HEIGHT = 100;
constant DEFAULT_LEVEL_HEIGHT (line 3) | const DEFAULT_LEVEL_HEIGHT = 200;
constant DEFAULT_HEIGHT_DECREMENT (line 10) | const DEFAULT_HEIGHT_DECREMENT = 200;
constant ANIMATION_DURATION (line 12) | const ANIMATION_DURATION = 800;
constant MATCH_TRANSLATE_REGEX (line 14) | const MATCH_TRANSLATE_REGEX = /translate\((-?\d+)px, ?(-?\d+)px\)/i;
constant MATCH_SCALE_REGEX (line 15) | const MATCH_SCALE_REGEX = /scale\((\S*)\)/i;
FILE: packages/tree-chart-core/src/tree-chart/index.ts
type TreeConfig (line 7) | interface TreeConfig {
type TreeChartCoreParams (line 14) | interface TreeChartCoreParams {
class TreeChartCore (line 25) | class TreeChartCore {
method constructor (line 49) | constructor(params: TreeChartCoreParams) {
method init (line 62) | init() {
method getNodeDataList (line 68) | getNodeDataList() {
method getInitialTransformStyle (line 72) | getInitialTransformStyle(): Record<string, string> {
method zoomIn (line 79) | zoomIn() {
method zoomOut (line 91) | zoomOut() {
method restoreScale (line 103) | restoreScale() {
method setScale (line 107) | setScale(scaleNum) {
method getTranslate (line 116) | getTranslate() {
method isVertical (line 128) | isVertical() {
method generateLinkPath (line 134) | private generateLinkPath(d) {
method generateCurceLinkPath (line 145) | private generateCurceLinkPath(self: this, d: any) {
method generateStraightLinkPath (line 178) | private generateStraightLinkPath(d: any) {
method updateDataList (line 201) | updateDataList() {
method draw (line 211) | private draw() {
method updatedInternalData (line 286) | private updatedInternalData(externalData) {
method buildTree (line 299) | private buildTree() {
method enableDrag (line 307) | private enableDrag() {
method initTransform (line 356) | initTransform() {
method onClickNode (line 372) | onClickNode(index: number) {
method updateDataset (line 393) | updateDataset(dataset: TreeDataset) {
method updateDirection (line 403) | updateDirection(direction: Direction) {
method updateLinks (line 413) | private updateLinks() {
method destroy (line 460) | destroy() {
FILE: packages/tree-chart-core/src/tree-chart/tree-chart.ts
type Direction (line 2) | enum Direction {
type TreeLinkStyle (line 7) | enum TreeLinkStyle {
type TreeDataset (line 12) | type TreeDataset = Object | Object[];
FILE: packages/tree-chart-core/src/tree-chart/util.ts
function rotatePoint (line 3) | function rotatePoint({ x, y }: { x: number; y: number }) {
function deepCopy (line 15) | function deepCopy(node) {
FILE: packages/tree-chart-demo/src/base/color-util.ts
function randomColor (line 1) | function randomColor(): string {
function appendFront0 (line 27) | function appendFront0(numStr: string): string {
function getColorStrFromCanvas (line 31) | function getColorStrFromCanvas(
FILE: packages/tree-chart-demo/src/base/data-generator.ts
type Data (line 1) | interface Data {
function generateOrgChartData (line 7) | function generateOrgChartData(depth: number) {
function generateOrgChartDataFolded (line 76) | function generateOrgChartDataFolded(depth: any, foldDepth: number) {
FILE: packages/tree-chart-demo/src/base/utils.ts
function text (line 1) | function text(ctx, text, x: number, y: number, fontSize, fontColor: stri...
function wrapText (line 7) | function wrapText(
function roundRect (line 34) | function roundRect(
FILE: packages/tree-chart-demo/src/base/uuid.ts
function uuid (line 2) | function uuid(): string {
FILE: packages/tree-chart-demo/src/components/org-chart.ts
class OrgChart (line 5) | class OrgChart {
method constructor (line 30) | constructor() {
method init (line 35) | init() {
method initVariables (line 42) | initVariables() {
method draw (line 58) | draw(data) {
method update (line 71) | update(targetTreeNode) {
method updateOrgUnits (line 106) | updateOrgUnits(
method updateLinks (line 168) | updateLinks(
method initCanvas (line 253) | initCanvas() {
method initVirtualNode (line 272) | initVirtualNode() {
method addColorKey (line 278) | addColorKey() {
method bindNodeToTreeData (line 293) | bindNodeToTreeData() {
method drawCanvas (line 303) | drawCanvas() {
method drawShowCanvas (line 308) | drawShowCanvas() {
method drawHiddenCanvas (line 378) | drawHiddenCanvas() {
method setCanvasListener (line 398) | setCanvasListener() {
method setClickListener (line 404) | setClickListener() {
method setMouseWheelZoomListener (line 420) | setMouseWheelZoomListener() {
method setDragListener (line 432) | setDragListener() {
method toggleTreeNode (line 471) | toggleTreeNode(treeNode) {
method bigger (line 481) | bigger() {
method smaller (line 489) | smaller() {
method clearCanvas_ (line 498) | clearCanvas_() {
FILE: packages/tree-chart-demo/src/demo/router/constant.ts
constant SVG_TREE (line 1) | const SVG_TREE = 'svgTree'
constant CANVAS_TREE (line 2) | const CANVAS_TREE = 'canvasTree'
constant JSON_VIEWER (line 3) | const JSON_VIEWER = 'jsonViewer'
FILE: packages/vue-tree-chart/library/vue-tree-chart.js
function __webpack_require__ (line 5999) | function __webpack_require__(moduleId) {
FILE: packages/vue-tree-chart/src/base/uuid.ts
function uuid (line 2) | function uuid(): string {
FILE: packages/vue3-tree-chart/src/base/uuid.js
function uuid (line 2) | function uuid() {
Condensed preview — 99 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,830K chars).
[
{
"path": ".github/workflows/build.yml",
"chars": 1124,
"preview": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versi"
},
{
"path": ".github/workflows/deploy.yml",
"chars": 1122,
"preview": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versi"
},
{
"path": ".github/workflows/release.yml",
"chars": 875,
"preview": "# This workflow will do a clean install of node dependencies, build the source code and run tests across different versi"
},
{
"path": ".gitignore",
"chars": 210,
"preview": ".DS_Store\nnode_modules/\ndist\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nbuilt/ # Ignore out dir in tsco"
},
{
"path": ".npmrc",
"chars": 22,
"preview": "legacy-peer-deps=true\n"
},
{
"path": "LICENSE.md",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2021 Shen Shuntian\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "README-CN.md",
"chars": 606,
"preview": "## [English](./README.md) | [中文](./README-CN.md)\n\n## Demo 页面\n\nhttps://ssthouse.github.io/tree-chart/#/svgTree\n\n## Demo 动"
},
{
"path": "README.md",
"chars": 743,
"preview": "## [English](./README.md) | [中文](./README-CN.md)\n\n\n## Demo\n\nhttps://ssthouse.github.io/tree-chart/#/svgTree\n\n## Demo Gif"
},
{
"path": "docs/canvas-tree-chart-CN.md",
"chars": 568,
"preview": "# Canvas Tree Chart\n\n## Canvas 版本 使用到的技术点\n\n- 将 D3.js 和 Canvas 一起使用,提升绘制效率(其中 D3.js 使用虚拟 DOM 就行渲染,Canvas 取虚拟 DOM 节点坐标进行绘制"
},
{
"path": "docs/canvas-tree-chart.md",
"chars": 711,
"preview": "# Canvas Tree Chart\n\n## Canvas version Using Tech\n\n- use D3.js with Canvas to draw organizationChart more efficiently.\n-"
},
{
"path": "docs/react-tree-chart.md",
"chars": 498,
"preview": "## Demo page\n\nhttps://codesandbox.io/s/react-tree-chart-544i2?file=/src/App.tsx\n\n## How to use?\n\n#### 1. install npm mod"
},
{
"path": "docs/tech-underneath.md",
"chars": 183,
"preview": "## Using Tech\n\n### Svg version\n\n- use D3 to calculate node & link positon\n- use Vue to handle dom element entring and le"
},
{
"path": "docs/vue-tree-chart-CN.md",
"chars": 8306,
"preview": "## [English](./vue-tree-chart.md)\n\n## Demo 页面\n\nhttps://ssthouse.github.io/tree-chart/#/svgTree\n\n## Demo 动图\n\n\n\n {\n return (\n <div clas"
},
{
"path": "packages/react-tree-chart/src/demo/index.css",
"chars": 366,
"preview": "body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Can"
},
{
"path": "packages/react-tree-chart/src/demo/react-app-env.d.ts",
"chars": 40,
"preview": "/// <reference types=\"react-scripts\" />\n"
},
{
"path": "packages/react-tree-chart/src/index.css",
"chars": 366,
"preview": "body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Can"
},
{
"path": "packages/react-tree-chart/src/index.tsx",
"chars": 1529,
"preview": "import React, { useRef, useState } from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport TreeChar"
},
{
"path": "packages/react-tree-chart/src/react-app-env.d.ts",
"chars": 40,
"preview": "/// <reference types=\"react-scripts\" />\n"
},
{
"path": "packages/react-tree-chart/src/setupTests.ts",
"chars": 241,
"preview": "// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).to"
},
{
"path": "packages/react-tree-chart/src/tree-chart/react-tree-chart.scss",
"chars": 1160,
"preview": ".tree-node-item-enter {\n opacity: 0.01;\n}\n\n.tree-node-item-enter.tree-node-item-enter-active {\n opacity: 1;\n transiti"
},
{
"path": "packages/react-tree-chart/src/tree-chart/react-tree-chart.tsx",
"chars": 5059,
"preview": "import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';\nimport TreeChartCore, { DEF"
},
{
"path": "packages/react-tree-chart/src/tree-chart/typings.d.ts",
"chars": 39,
"preview": "declare module 'react-transition-group'"
},
{
"path": "packages/react-tree-chart/tsconfig.json",
"chars": 551,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"es5\",\n \"declaration\": true,\n \"lib\": [\n \"dom\",\n \"dom.iterable\",\n "
},
{
"path": "packages/tree-chart-core/.eslintrc.js",
"chars": 130,
"preview": "module.exports = {\n \"extends\": \"eslint:recommended\",\n \"parserOptions\": {\n \"sourceType\": \"module\",\n ecmaVersion: "
},
{
"path": "packages/tree-chart-core/.gitignore",
"chars": 5,
"preview": "build"
},
{
"path": "packages/tree-chart-core/package.json",
"chars": 576,
"preview": "{\n \"name\": \"@ssthouse/tree-chart-core\",\n \"version\": \"1.2.0\",\n \"description\": \"tree chart's core logic (shared by Vue2"
},
{
"path": "packages/tree-chart-core/src/base/uuid.ts",
"chars": 314,
"preview": "\nexport function uuid(): string {\n const s = []\n const hexDigits = '0123456789abcdef'\n for (let i = 0; i < 36; i++) {"
},
{
"path": "packages/tree-chart-core/src/index.ts",
"chars": 159,
"preview": "import TreeChartCore from \"./tree-chart/index\";\n\nexport default TreeChartCore;\n\nexport * from './tree-chart/constant';\ne"
},
{
"path": "packages/tree-chart-core/src/tree-chart/constant.ts",
"chars": 521,
"preview": "export const DEFAULT_NODE_WIDTH = 100;\nexport const DEFAULT_NODE_HEIGHT = 100;\nexport const DEFAULT_LEVEL_HEIGHT = 200;\n"
},
{
"path": "packages/tree-chart-core/src/tree-chart/index.ts",
"chars": 13382,
"preview": "import * as d3 from 'd3';\nimport { ANIMATION_DURATION, DEFAULT_HEIGHT_DECREMENT, DEFAULT_LEVEL_HEIGHT, DEFAULT_NODE_HEIG"
},
{
"path": "packages/tree-chart-core/src/tree-chart/tree-chart.ts",
"chars": 202,
"preview": "\nexport enum Direction {\n VERTICAL = \"vertical\",\n HORIZONTAL = \"horizontal\",\n}\n\nexport enum TreeLinkStyle {\n CURVE = "
},
{
"path": "packages/tree-chart-core/src/tree-chart/util.ts",
"chars": 704,
"preview": "import { uuid } from \"../base/uuid\";\n\nexport function rotatePoint({ x, y }: { x: number; y: number }) {\n return {\n x"
},
{
"path": "packages/tree-chart-core/tsconfig.json",
"chars": 266,
"preview": "{\n \"compilerOptions\": {\n \"outDir\": \"./build/\",\n \"sourceMap\": false,\n \"strict\": false,\n \"noImplicitReturns\":"
},
{
"path": "packages/tree-chart-demo/build/webpack.config.base.js",
"chars": 1111,
"preview": "const path = require('path')\nconst { VueLoaderPlugin } = require('vue-loader')\nconst HtmlWebpackPlugin = require('html-w"
},
{
"path": "packages/tree-chart-demo/build/webpack.config.dev.js",
"chars": 186,
"preview": "const merge = require('webpack-merge')\n\nmodule.exports = merge(require('./webpack.config.base'), {\n mode: 'development'"
},
{
"path": "packages/tree-chart-demo/build/webpack.config.prod.js",
"chars": 263,
"preview": "const merge = require('webpack-merge')\nconst webpack = require('webpack')\n\nmodule.exports = merge(require('./webpack.con"
},
{
"path": "packages/tree-chart-demo/package.json",
"chars": 2746,
"preview": "{\n\t\"name\": \"tree-chart-demo\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"tree chart demo page\",\n\t\"main\": \"index.js\",\n\t\"author"
},
{
"path": "packages/tree-chart-demo/src/base/color-util.ts",
"chars": 746,
"preview": "export function randomColor(): string {\n const letters = [\n '0',\n '1',\n '2',\n '3',\n '4',\n '5',\n '6"
},
{
"path": "packages/tree-chart-demo/src/base/data-generator.ts",
"chars": 2130,
"preview": "export interface Data {\n name: string\n title: string\n children: any\n}\n\nexport function generateOrgChartData(depth: nu"
},
{
"path": "packages/tree-chart-demo/src/base/utils.ts",
"chars": 1996,
"preview": "function text(ctx, text, x: number, y: number, fontSize, fontColor: string) {\n ctx.font = '14px Arial'\n ctx.fillStyle "
},
{
"path": "packages/tree-chart-demo/src/base/uuid.ts",
"chars": 314,
"preview": "\nexport function uuid(): string {\n const s = []\n const hexDigits = '0123456789abcdef'\n for (let i = 0; i < 36; i++) {"
},
{
"path": "packages/tree-chart-demo/src/components/CanvasTree.vue",
"chars": 2023,
"preview": "<template>\n <div id=\"org-chart-container\">\n <div class=\"menu-container\">\n <v-layout row>\n <v-btn @click="
},
{
"path": "packages/tree-chart-demo/src/components/VueTreeDemo.vue",
"chars": 11187,
"preview": "<template>\n <div class=\"container\">\n <h3>Basic usage | 基本使用</h3>\n\n <vue-tree\n style=\"width: 800px; height: 6"
},
{
"path": "packages/tree-chart-demo/src/components/org-chart.ts",
"chars": 12558,
"preview": "import * as d3 from 'd3'\nimport Util from '../base/utils'\nimport { randomColor, getColorStrFromCanvas } from '../base/co"
},
{
"path": "packages/tree-chart-demo/src/demo/App.vue",
"chars": 2141,
"preview": "<template>\n <v-app>\n <v-toolbar>\n <v-toolbar-side-icon></v-toolbar-side-icon>\n <v-toolbar-title>Tree Chart"
},
{
"path": "packages/tree-chart-demo/src/demo/google-icon.css",
"chars": 9798,
"preview": "/* fallback */\n@font-face {\n font-family: 'Material Icons';\n font-style: normal;\n font-weight: 400;\n src: url(https:"
},
{
"path": "packages/tree-chart-demo/src/demo/main.ts",
"chars": 476,
"preview": "// The Vue build version to load with the `import` command\n// (runtime-only or standalone) has been set in webpack.base."
},
{
"path": "packages/tree-chart-demo/src/demo/router/constant.ts",
"chars": 114,
"preview": "export const SVG_TREE = 'svgTree'\nexport const CANVAS_TREE = 'canvasTree'\nexport const JSON_VIEWER = 'jsonViewer'\n"
},
{
"path": "packages/tree-chart-demo/src/demo/router/index.ts",
"chars": 530,
"preview": "import Vue from 'vue'\nimport Router from 'vue-router'\nimport CanvasTree from '../../components/CanvasTree.vue'\nimport Vu"
},
{
"path": "packages/tree-chart-demo/src/vue.shims.d.ts",
"chars": 72,
"preview": "declare module '*.vue' {\n import Vue from 'vue'\n export default Vue\n}\n"
},
{
"path": "packages/tree-chart-demo/template/index.html",
"chars": 320,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width,initi"
},
{
"path": "packages/tree-chart-demo/tsconfig.json",
"chars": 235,
"preview": "{\n \"compilerOptions\": {\n \"outDir\": \"./build/\",\n \"sourceMap\": true,\n \"strict\": false,\n \"noImplicitReturns\": "
},
{
"path": "packages/vue-tree-chart/.babelrc",
"chars": 230,
"preview": "{\n \"presets\": [\n [\"env\", {\n \"modules\": false,\n \"targets\": {\n \"browsers\": [\"> 1%\", \"last 2 versions\""
},
{
"path": "packages/vue-tree-chart/.editorconfig",
"chars": 147,
"preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
},
{
"path": "packages/vue-tree-chart/.eslintignore",
"chars": 56,
"preview": "/build/\n/config/\n/dist/\n/*.js\nlibrary/*.js\nsrc/**/*d.ts\n"
},
{
"path": "packages/vue-tree-chart/.eslintrc.js",
"chars": 454,
"preview": "module.exports = {\n root: true,\n env: {\n 'node': true\n },\n extends: [\n 'plugin:vue/essential',\n '@vue/types"
},
{
"path": "packages/vue-tree-chart/.postcssrc.js",
"chars": 246,
"preview": "// https://github.com/michael-ciniawsky/postcss-load-config\n\nmodule.exports = {\n \"plugins\": {\n \"postcss-import\": {},"
},
{
"path": "packages/vue-tree-chart/.prettierignore",
"chars": 43,
"preview": "/build/\n/config/\n/dist/\n/*.js\nlibrary/*.js\n"
},
{
"path": "packages/vue-tree-chart/README.md",
"chars": 223,
"preview": "# @ssthouse/vue-tree-chart\n\n## Docs \n\n(https://github.com/ssthouse/vue-tree-chart)[https://github.com/ssthouse/vue-tree-"
},
{
"path": "packages/vue-tree-chart/build/webpack.config.base.js",
"chars": 1111,
"preview": "const path = require('path')\nconst { VueLoaderPlugin } = require('vue-loader')\nconst HtmlWebpackPlugin = require('html-w"
},
{
"path": "packages/vue-tree-chart/build/webpack.config.dev.js",
"chars": 186,
"preview": "const merge = require('webpack-merge')\n\nmodule.exports = merge(require('./webpack.config.base'), {\n mode: 'development'"
},
{
"path": "packages/vue-tree-chart/build/webpack.config.library.js",
"chars": 1019,
"preview": "const path = require('path')\nconst { VueLoaderPlugin } = require('vue-loader')\n\nmodule.exports = {\n mode: 'development'"
},
{
"path": "packages/vue-tree-chart/library/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "packages/vue-tree-chart/library/vue-tree-chart.js",
"chars": 1612294,
"preview": "/*\n * ATTENTION: The \"eval\" devtool has been used (maybe by default in mode: \"development\").\n * This devtool is neither "
},
{
"path": "packages/vue-tree-chart/package.json",
"chars": 2847,
"preview": "{\n\t\"name\": \"@ssthouse/vue-tree-chart\",\n\t\"version\": \"0.7.0\",\n\t\"description\": \"Tree Component for Vue2 powered by D3.js & "
},
{
"path": "packages/vue-tree-chart/src/base/uuid.ts",
"chars": 314,
"preview": "\nexport function uuid(): string {\n const s = []\n const hexDigits = '0123456789abcdef'\n for (let i = 0; i < 36; i++) {"
},
{
"path": "packages/vue-tree-chart/src/demo/App.vue",
"chars": 1222,
"preview": "<template>\n <div>\n <h1>Vue2</h1>\n <button @click=\"onChangeDataset\">change dataset</button>\n\n <vue-tree\n s"
},
{
"path": "packages/vue-tree-chart/src/demo/main.ts",
"chars": 123,
"preview": "import Vue from 'vue';\nimport App from './App.vue'\n\nnew Vue({\n el: '#app',\n components: { App },\n template: '<App/>'\n"
},
{
"path": "packages/vue-tree-chart/src/vue-tree/VueTree.vue",
"chars": 5118,
"preview": "<template>\n <div class=\"tree-container\" ref=\"container\">\n <svg class=\"svg vue-tree\" ref=\"svg\" :style=\"initialTransfo"
},
{
"path": "packages/vue-tree-chart/src/vue-tree/index.ts",
"chars": 60,
"preview": "import VueTree from './VueTree.vue'\n\nexport default VueTree\n"
},
{
"path": "packages/vue-tree-chart/src/vue.shims.d.ts",
"chars": 72,
"preview": "declare module '*.vue' {\n import Vue from 'vue'\n export default Vue\n}\n"
},
{
"path": "packages/vue-tree-chart/template/index.html",
"chars": 555,
"preview": "<!DOCTYPE html>\n<html lang=\"\">\n <head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "packages/vue-tree-chart/tsconfig.json",
"chars": 235,
"preview": "{\n \"compilerOptions\": {\n \"outDir\": \"./build/\",\n \"sourceMap\": true,\n \"strict\": false,\n \"noImplicitReturns\": "
},
{
"path": "packages/vue3-tree-chart/.gitignore",
"chars": 231,
"preview": ".DS_Store\nnode_modules\n/dist\n\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyar"
},
{
"path": "packages/vue3-tree-chart/README.md",
"chars": 224,
"preview": "# @ssthouse/vue3-tree-chart\n\n## Docs \n\n[https://github.com/ssthouse/vue-tree-chart](https://github.com/ssthouse/vue-tree"
},
{
"path": "packages/vue3-tree-chart/babel.config.js",
"chars": 73,
"preview": "module.exports = {\n presets: [\n '@vue/cli-plugin-babel/preset'\n ]\n}\n"
},
{
"path": "packages/vue3-tree-chart/package.json",
"chars": 1421,
"preview": "{\n \"name\": \"@ssthouse/vue3-tree-chart\",\n \"author\": \"ssthouse\",\n \"version\": \"0.3.0\",\n \"description\": \"Tree Component "
},
{
"path": "packages/vue3-tree-chart/public/index.html",
"chars": 611,
"preview": "<!DOCTYPE html>\n<html lang=\"\">\n <head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "packages/vue3-tree-chart/src/App.vue",
"chars": 1193,
"preview": "<template>\n <div>\n <h1>Vue3</h1>\n\n <button @click=\"onChangeDataset\">change dataset</button>\n\n <vue-tree\n "
},
{
"path": "packages/vue3-tree-chart/src/base/uuid.js",
"chars": 306,
"preview": "\nexport function uuid() {\n const s = []\n const hexDigits = '0123456789abcdef'\n for (let i = 0; i < 36; i++) {\n s[i"
},
{
"path": "packages/vue3-tree-chart/src/components/HelloWorld.vue",
"chars": 2025,
"preview": "<template>\n <div class=\"hello\">\n <h1>{{ msg }}</h1>\n <p>\n For a guide and recipes on how to configure / cust"
},
{
"path": "packages/vue3-tree-chart/src/main.js",
"chars": 90,
"preview": "import { createApp } from 'vue'\nimport App from './App.vue'\n\ncreateApp(App).mount('#app')\n"
},
{
"path": "packages/vue3-tree-chart/src/vue-tree/VueTree.vue",
"chars": 5117,
"preview": "<template>\n <div class=\"tree-container\" ref=\"container\">\n <svg class=\"svg vue-tree\" ref=\"svg\" :style=\"initialTransfo"
},
{
"path": "packages/vue3-tree-chart/src/vue-tree/index.js",
"chars": 74,
"preview": "// @ts-ignore\nimport VueTree from './VueTree.vue'\n\nexport default VueTree\n"
},
{
"path": "packages/vue3-tree-chart/vite.config.js",
"chars": 46,
"preview": "module.exports = {\n css: { extract: false }\n}"
},
{
"path": "scripts/publish-safe.sh",
"chars": 582,
"preview": "#!/bin/bash\n# Safe publish script that skips if version already exists\nnpm publish 2>&1 | tee /tmp/npm-publish-$$.log\nEX"
}
]
About this extraction
This page contains the full source code of the ssthouse/vue-tree-chart GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 99 files (1.7 MB), approximately 500.9k tokens, and a symbol index with 87 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.