123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867 |
- <template>
- <div style="height: 100%">
- <a-select
- show-search
- label-in-value
- :value="value"
- placeholder="选择公司"
- style="width: 400px"
- :filter-option="false"
- :not-found-content="fetching ? undefined : null"
- @search="fetchQuotedCompany"
- @change="handleChange"
- @focus="fetchQuotedCompany"
- >
- <a-spin v-if="fetching" slot="notFoundContent" size="small" />
- <a-select-option v-for="d in quotedCompanys" :key="d.id">
- {{ d.name }}
- </a-select-option>
- </a-select>
- <div id="appc" style="height: 98%"></div>
- </div>
- </template>
- <script>
- import * as $d3 from 'd3'
- import axios from '@/common/services/axios-instance'
- import debounce from 'lodash/debounce'
- export default {
- name: 'Legalperson',
- data() {
- this.fetchQuotedCompany = debounce(this.fetchQuotedCompany, 800)
- return {
- d3: $d3,
- cachedTreeData: {},
- treeData: {},
- allQuotedCompanys: [],
- quotedCompanys: [],
- value: [],
- fetching: false,
- }
- },
- mounted() {
- axios.get('api/xcoa-mobile/v1/equityPenetration').then((res) => {
- if (res.data) {
- this.treeData = res.data
- this.cachedTreeData[2353689640] = this.treeData
- this.constructor()
- }
- })
- axios.get('api/xcoa-mobile/v1/quotedCompanys').then((res) => {
- if (res.data) {
- this.allQuotedCompanys = res.data
- }
- })
- },
- methods: {
- fetchQuotedCompany(value) {
- console.log('fetching user', value)
- this.quotedCompanys = []
- this.fetching = true
- if (value) {
- const filtedC = this.allQuotedCompanys.filter((c) => c.name.includes(value))
- if (filtedC.length > 200) {
- const t = filtedC.slice(0, 200)
- t.push({ id: -1, name: '200+ ......' })
- this.quotedCompanys = t
- } else {
- this.quotedCompanys = filtedC
- }
- } else {
- this.quotedCompanys = this.allQuotedCompanys.slice(0, 200)
- this.quotedCompanys.push({ id: -1, name: '200+ ......' })
- }
- this.fetching = false
- },
- handleChange(value) {
- console.log(value)
- if (value.key === -1) {
- return false
- }
- Object.assign(this, {
- value,
- quotedCompanys: [],
- fetching: false,
- })
- const companyId = value.key
- if (this.cachedTreeData[companyId]) {
- console.log('loadFromCache')
- this.treeData = this.cachedTreeData[companyId]
- document.getElementById('appc').innerHTML = ''
- this.constructor()
- } else {
- axios
- .get('api/xcoa-mobile/v1/equityPenetration?quotedCompanyId=' + companyId)
- .then((res) => {
- if (res.data) {
- console.log('loadFromNetwork')
- this.treeData = res.data
- this.cachedTreeData[companyId] = this.treeData
- document.getElementById('appc').innerHTML = ''
- this.constructor()
- }
- })
- }
- console.log(value)
- },
- // 股权树
- constructor(options) {
- // 树的源数据
- this.originTreeData = this.treeData
- // 宿主元素选择器
- this.el = document.getElementById('appc')
- // 一些配置项
- this.config = {
- // 节点的横向距离
- dx: 200,
- // 节点的纵向距离
- dy: 170,
- // svg的viewBox的宽度
- width: 0,
- // svg的viewBox的高度
- height: 500,
- // 节点的矩形框宽度
- rectWidth: 170,
- // 节点的矩形框高度
- rectHeight: 70,
- }
- this.svg = null
- this.gAll = null
- this.gLinks = null
- this.gNodes = null
- // 给树加坐标点的方法
- this.tree = null
- // 投资公司树的根节点
- this.rootOfDown = null
- // 股东树的根节点
- this.rootOfUp = null
- this.drawChart({
- type: 'fold',
- })
- },
- // 初始化树结构数据
- drawChart(options) {
- // 宿主元素的d3选择器对象
- const host = this.d3.select(this.el)
- // 宿主元素的DOM,通过node()获取到其DOM元素对象
- const dom = host.node()
- // 宿主元素的DOMRect
- const domRect = dom.getBoundingClientRect()
- // svg的宽度和高度
- this.config.width = domRect.width
- this.config.height = domRect.height
- const oldSvg = this.d3.select('svg')
- // 如果宿主元素中包含svg标签了,那么则删除这个标签,再重新生成一个
- if (!oldSvg.empty()) {
- oldSvg.remove()
- }
- const svg = this.d3
- .create('svg')
- .attr('viewBox', () => {
- const parentsLength = this.originTreeData.parents ? this.originTreeData.parents.length : 0
- return [
- -this.config.width / 2,
- // 如果有父节点,则根节点居中,否则根节点上浮一段距离
- parentsLength > 0 ? -this.config.height / 2 : -this.config.height / 3,
- this.config.width,
- this.config.height,
- ]
- })
- .style('user-select', 'none')
- .style('cursor', 'move')
- // 包括连接线和节点的总集合
- const gAll = svg.append('g').attr('id', 'all')
- svg
- .call(
- this.d3
- .zoom()
- .scaleExtent([0.2, 5])
- .on('zoom', (e) => {
- gAll.attr('transform', () => {
- return `translate(${e.transform.x},${e.transform.y}) scale(${e.transform.k})`
- })
- })
- )
- .on('dblclick.zoom', null) // 取消默认的双击放大事件
- this.gAll = gAll
- // 连接线集合
- this.gLinks = gAll.append('g').attr('id', 'linkGroup')
- // 节点集合
- this.gNodes = gAll.append('g').attr('id', 'nodeGroup')
- // 设置好节点之间距离的tree方法
- this.tree = this.d3.tree().nodeSize([this.config.dx, this.config.dy])
- this.rootOfDown = this.d3.hierarchy(this.originTreeData, (d) => d.children)
- this.rootOfUp = this.d3.hierarchy(this.originTreeData, (d) => d.parents)
- this.tree(this.rootOfDown)
- ;[this.rootOfDown.descendants(), this.rootOfUp.descendants()].forEach((nodes) => {
- nodes.forEach((node) => {
- node._children = node.children || null
- if (options.type === 'all') {
- // 如果是all的话,则表示全部都展开
- node.children = node._children
- } else if (options.type === 'fold') {
- // 如果是fold则表示除了父节点全都折叠
- // 将非根节点的节点都隐藏掉(其实对于这个组件来说加不加都一样)
- if (node.depth) {
- node.children = null
- }
- }
- })
- })
- // 箭头(下半部分)
- svg
- .append('marker')
- .attr('id', 'markerOfDown')
- .attr('markerUnits', 'userSpaceOnUse')
- .attr('viewBox', '0 -5 10 10') // 坐标系的区域
- .attr('refX', 55) // 箭头坐标
- .attr('refY', 0)
- .attr('markerWidth', 10) // 标识的大小
- .attr('markerHeight', 10)
- .attr('orient', '90') // 绘制方向,可设定为:auto(自动确认方向)和 角度值
- .attr('stroke-width', 2) // 箭头宽度
- .append('path')
- .attr('d', 'M0,-5L10,0L0,5') // 箭头的路径
- .attr('fill', '#215af3') // 箭头颜色
- // 箭头(上半部分)
- svg
- .append('marker')
- .attr('id', 'markerOfUp')
- .attr('markerUnits', 'userSpaceOnUse')
- .attr('viewBox', '0 -5 10 10') // 坐标系的区域
- .attr('refX', -50) // 箭头坐标
- .attr('refY', 0)
- .attr('markerWidth', 10) // 标识的大小
- .attr('markerHeight', 10)
- .attr('orient', '90') // 绘制方向,可设定为:auto(自动确认方向)和 角度值
- .attr('stroke-width', 2) // 箭头宽度
- .append('path')
- .attr('d', 'M0,-5L10,0L0,5') // 箭头的路径
- .attr('fill', '#215af3') // 箭头颜色
- this.svg = svg
- this.update()
- // 将svg置入宿主元素中
- host.append(function() {
- return svg.node()
- })
- },
- // 更新数据
- update(source) {
- if (!source) {
- source = {
- x0: 0,
- y0: 0,
- }
- // 设置根节点所在的位置(原点)
- this.rootOfDown.x0 = 0
- this.rootOfDown.y0 = 0
- this.rootOfUp.x0 = 0
- this.rootOfUp.y0 = 0
- }
- const nodesOfDown = this.rootOfDown.descendants().reverse()
- const linksOfDown = this.rootOfDown.links()
- const nodesOfUp = this.rootOfUp.descendants().reverse()
- const linksOfUp = this.rootOfUp.links()
- this.tree(this.rootOfDown)
- this.tree(this.rootOfUp)
- const myTransition = this.svg.transition().duration(500)
- /** * 绘制子公司树 ***/
- const node1 = this.gNodes.selectAll('g.nodeOfDownItemGroup').data(nodesOfDown, (d) => {
- return d.data.id
- })
- const node1Enter = node1
- .enter()
- .append('g')
- .attr('class', 'nodeOfDownItemGroup')
- .attr('transform', (d) => {
- return `translate(${source.x0},${source.y0})`
- })
- .attr('fill-opacity', 0)
- .attr('stroke-opacity', 0)
- .style('cursor', 'pointer')
- // 外层的矩形框
- node1Enter
- .append('rect')
- .attr('width', (d) => {
- if (d.depth === 0) {
- return (d.data.name.length + 2) * 16
- }
- return this.config.rectWidth
- })
- .attr('height', (d) => {
- if (d.depth === 0) {
- return 30
- }
- return this.config.rectHeight
- })
- .attr('x', (d) => {
- if (d.depth === 0) {
- return (-(d.data.name.length + 2) * 16) / 2
- }
- return -this.config.rectWidth / 2
- })
- .attr('y', (d) => {
- if (d.depth === 0) {
- return -15
- }
- return -this.config.rectHeight / 2
- })
- .attr('rx', 5)
- .attr('stroke-width', 1)
- .attr('stroke', (d) => {
- if (d.depth === 0) {
- return '#5682ec'
- }
- return '#7A9EFF'
- })
- .attr('fill', (d) => {
- if (d.depth === 0) {
- return '#7A9EFF'
- }
- return '#FFFFFF'
- })
- .on('click', (e, d) => {
- this.nodeClickEvent(e, d)
- })
- .on('dblclick', (e, d) => {})
- // 文本主标题
- node1Enter
- .append('text')
- .attr('class', 'main-title')
- .attr('x', (d) => {
- return 0
- })
- .attr('y', (d) => {
- if (d.depth === 0) {
- return 5
- }
- return -14
- })
- .attr('text-anchor', (d) => {
- return 'middle'
- })
- .text((d) => {
- if (d.depth === 0) {
- const levelStr = d.data.level ? '(' + d.data.level + ')' : ''
- if (levelStr && d.data.name.indexOf(levelStr) === -1) {
- d.data.name = d.data.name + levelStr
- }
- return d.data.name
- } else {
- const levelStr = d.data.level ? '(' + d.data.level + ')' : ''
- if (levelStr && d.data.name.indexOf(levelStr) === -1) {
- d.data.name = d.data.name + levelStr
- }
- return d.data.name.length > 11 ? d.data.name.substring(0, 11) : d.data.name
- }
- })
- .attr('fill', (d) => {
- if (d.depth === 0) {
- return '#FFFFFF'
- }
- return '#000000'
- })
- .style('font-size', (d) => (d.depth === 0 ? 16 : 14))
- .style(
- 'font-family',
- "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'"
- )
- .on('click', (e, d) => {
- this.nodeClickEvent(e, d)
- })
- .on('dblclick', (e, d) => {})
- // .style('font-weight', 'bold')
- // 副标题
- node1Enter
- .append('text')
- .attr('class', 'sub-title')
- .attr('x', (d) => {
- return 0
- })
- .attr('y', (d) => {
- return 5
- })
- .attr('text-anchor', (d) => {
- return 'middle'
- })
- .text((d) => {
- if (d.depth !== 0) {
- const subTitle = d.data.name.substring(11)
- if (subTitle.length > 10) {
- return subTitle.substring(0, 10) + '...'
- }
- return subTitle
- }
- })
- .style('font-size', (d) => 14)
- .style(
- 'font-family',
- "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'"
- )
- .on('click', (e, d) => {
- this.nodeClickEvent(e, d)
- })
- .on('dblclick', (e, d) => {})
- // .style('font-weight', 'bold')
- // 控股比例
- node1Enter
- .append('text')
- .attr('class', 'percent')
- .attr('x', (d) => {
- return 12
- })
- .attr('y', (d) => {
- return -45
- })
- .text((d) => {
- if (d.depth !== 0) {
- return d.data.percent
- }
- })
- .attr('fill', '#000000')
- .style(
- 'font-family',
- "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'"
- )
- .style('font-size', (d) => 14)
- // 增加展开按钮
- const expandBtnG = node1Enter
- .append('g')
- .attr('class', 'expandBtn')
- .attr('transform', (d) => {
- return `translate(${0},${this.config.rectHeight / 2})`
- })
- .style('display', (d) => {
- // 如果是根节点,不显示
- if (d.depth === 0) {
- return 'none'
- }
- // 如果没有子节点,则不显示
- if (!d._children) {
- return 'none'
- }
- })
- .on('click', (e, d) => {
- if (d.children) {
- d._children = d.children
- d.children = null
- } else {
- d.children = d._children
- }
- this.update(d)
- })
- expandBtnG
- .append('circle')
- .attr('r', 10)
- .attr('fill', '#7A9EFF')
- .attr('cy', 10)
- expandBtnG
- .append('text')
- .attr('text-anchor', 'middle')
- .attr('fill', '#ffffff')
- .attr('y', 14)
- .style('font-size', 16)
- .style('font-family', '微软雅黑')
- .text((d) => {
- return d.children ? '-' : '+'
- })
- const link1 = this.gLinks
- .selectAll('path.linkOfDownItem')
- .data(linksOfDown, (d) => d.target.data.id)
- const link1Enter = link1
- .enter()
- .append('path')
- .attr('class', 'linkOfDownItem')
- .attr('d', (d) => {
- const o = {
- source: {
- x: source.x0,
- y: source.y0,
- },
- target: {
- x: source.x0,
- y: source.y0,
- },
- }
- return this.drawLink(o)
- })
- .attr('fill', 'none')
- .attr('stroke', '#7A9EFF')
- .attr('stroke-width', 1)
- .attr('marker-end', 'url(#markerOfDown)')
- // 有元素update更新和元素新增enter的时候
- node1
- .merge(node1Enter)
- .transition(myTransition)
- .attr('transform', (d) => {
- return `translate(${d.x},${d.y})`
- })
- .attr('fill-opacity', 1)
- .attr('stroke-opacity', 1)
- // 有元素消失时
- node1
- .exit()
- .transition(myTransition)
- .remove()
- .attr('transform', (d) => {
- return `translate(${source.x0},${source.y0})`
- })
- .attr('fill-opacity', 0)
- .attr('stroke-opacity', 0)
- link1
- .merge(link1Enter)
- .transition(myTransition)
- .attr('d', this.drawLink)
- link1
- .exit()
- .transition(myTransition)
- .remove()
- .attr('d', (d) => {
- const o = {
- source: {
- x: source.x,
- y: source.y,
- },
- target: {
- x: source.x,
- y: source.y,
- },
- }
- return this.drawLink(o)
- })
- /** * 绘制股东树 ***/
- nodesOfUp.forEach((node) => {
- node.y = -node.y
- })
- const node2 = this.gNodes.selectAll('g.nodeOfUpItemGroup').data(nodesOfUp, (d) => {
- return d.data.id
- })
- const node2Enter = node2
- .enter()
- .append('g')
- .attr('class', 'nodeOfUpItemGroup')
- .attr('transform', (d) => {
- return `translate(${source.x0},${source.y0})`
- })
- .attr('fill-opacity', 0)
- .attr('stroke-opacity', 0)
- .style('cursor', 'pointer')
- // 外层的矩形框
- node2Enter
- .append('rect')
- .attr('width', (d) => {
- if (d.depth === 0) {
- return (d.data.name.length + 2) * 16
- }
- return this.config.rectWidth
- })
- .attr('height', (d) => {
- if (d.depth === 0) {
- return 30
- }
- return this.config.rectHeight
- })
- .attr('x', (d) => {
- if (d.depth === 0) {
- return (-(d.data.name.length + 2) * 16) / 2
- }
- return -this.config.rectWidth / 2
- })
- .attr('y', (d) => {
- if (d.depth === 0) {
- return -15
- }
- return -this.config.rectHeight / 2
- })
- .attr('rx', 5)
- .attr('stroke-width', 1)
- .attr('stroke', (d) => {
- if (d.depth === 0) {
- return '#5682ec'
- }
- return '#7A9EFF'
- })
- .attr('fill', (d) => {
- if (d.depth === 0) {
- return '#7A9EFF'
- }
- return '#FFFFFF'
- })
- .on('click', (e, d) => {
- this.nodeClickEvent(e, d)
- })
- // 文本主标题
- node2Enter
- .append('text')
- .attr('class', 'main-title')
- .attr('x', (d) => {
- return 0
- })
- .attr('y', (d) => {
- if (d.depth === 0) {
- return 5
- }
- return -14
- })
- .attr('text-anchor', (d) => {
- return 'middle'
- })
- .text((d) => {
- if (d.depth === 0) {
- return d.data.name
- } else {
- const levelStr = d.data.level ? '(' + d.data.level + ')' : ''
- if (levelStr && d.data.name.indexOf(levelStr) === -1) {
- d.data.name = d.data.name + levelStr
- }
- return d.data.name.length > 11 ? d.data.name.substring(0, 11) : d.data.name
- }
- })
- .attr('fill', (d) => {
- if (d.depth === 0) {
- return '#FFFFFF'
- }
- return '#000000'
- })
- .style('font-size', (d) => (d.depth === 0 ? 16 : 14))
- .style(
- 'font-family',
- "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'"
- )
- .on('click', (e, d) => {
- this.nodeClickEvent(e, d)
- })
- // .style('font-weight', 'bold')
- // 副标题
- node2Enter
- .append('text')
- .attr('class', 'sub-title')
- .attr('x', (d) => {
- return 0
- })
- .attr('y', (d) => {
- return 5
- })
- .attr('text-anchor', (d) => {
- return 'middle'
- })
- .text((d) => {
- if (d.depth !== 0) {
- const subTitle = d.data.name.substring(11)
- if (subTitle.length > 10) {
- return subTitle.substring(0, 10) + '...'
- }
- return subTitle
- }
- })
- .style('font-size', (d) => 14)
- .style(
- 'font-family',
- "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'"
- )
- // .style('font-weight', 'bold')
- // 控股比例
- node2Enter
- .append('text')
- .attr('class', 'percent')
- .attr('x', (d) => {
- return 12
- })
- .attr('y', (d) => {
- return 55
- })
- .text((d) => {
- if (d.depth !== 0) {
- return d.data.percent
- }
- })
- .attr('fill', '#000000')
- .style(
- 'font-family',
- "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'"
- )
- .style('font-size', (d) => 14)
- // 增加展开按钮
- const expandBtnG2 = node2Enter
- .append('g')
- .attr('class', 'expandBtn')
- .attr('transform', (d) => {
- return `translate(${0},${-this.config.rectHeight / 2})`
- })
- .style('display', (d) => {
- // 如果是根节点,不显示
- if (d.depth === 0) {
- return 'none'
- }
- // 如果没有子节点,则不显示
- if (!d._children) {
- return 'none'
- }
- })
- .on('click', (e, d) => {
- if (d.children) {
- d._children = d.children
- d.children = null
- } else {
- d.children = d._children
- }
- this.update(d)
- })
- expandBtnG2
- .append('circle')
- .attr('r', 10)
- .attr('fill', '#7A9EFF')
- .attr('cy', -10)
- expandBtnG2
- .append('text')
- .attr('text-anchor', 'middle')
- .attr('fill', '#ffffff')
- .attr('y', -7)
- .style('font-size', 16)
- .style('font-family', '微软雅黑')
- .text((d) => {
- return d.children ? '-' : '+'
- })
- const link2 = this.gLinks
- .selectAll('path.linkOfUpItem')
- .data(linksOfUp, (d) => d.target.data.id)
- const link2Enter = link2
- .enter()
- .append('path')
- .attr('class', 'linkOfUpItem')
- .attr('d', (d) => {
- const o = {
- source: {
- x: source.x0,
- y: source.y0,
- },
- target: {
- x: source.x0,
- y: source.y0,
- },
- }
- return this.drawLink(o)
- })
- .attr('fill', 'none')
- .attr('stroke', '#7A9EFF')
- .attr('stroke-width', 1)
- .attr('marker-end', 'url(#markerOfUp)')
- // 有元素update更新和元素新增enter的时候
- node2
- .merge(node2Enter)
- .transition(myTransition)
- .attr('transform', (d) => {
- return `translate(${d.x},${d.y})`
- })
- .attr('fill-opacity', 1)
- .attr('stroke-opacity', 1)
- // 有元素消失时
- node2
- .exit()
- .transition(myTransition)
- .remove()
- .attr('transform', (d) => {
- return `translate(${source.x0},${source.y0})`
- })
- .attr('fill-opacity', 0)
- .attr('stroke-opacity', 0)
- link2
- .merge(link2Enter)
- .transition(myTransition)
- .attr('d', this.drawLink)
- link2
- .exit()
- .transition(myTransition)
- .remove()
- .attr('d', (d) => {
- const o = {
- source: {
- x: source.x,
- y: source.y,
- },
- target: {
- x: source.x,
- y: source.y,
- },
- }
- return this.drawLink(o)
- })
- // node数据改变的时候更改一下加减号
- const expandButtonsSelection = this.d3.selectAll('g.expandBtn')
- expandButtonsSelection
- .select('text')
- .transition()
- .text((d) => {
- return d.children ? '-' : '+'
- })
- this.rootOfDown.eachBefore((d) => {
- d.x0 = d.x
- d.y0 = d.y
- })
- this.rootOfUp.eachBefore((d) => {
- d.x0 = d.x
- d.y0 = d.y
- })
- },
- // 直角连接线 by wushengyuan
- drawLink({ source, target }) {
- const halfDistance = (target.y - source.y) / 2
- const halfY = source.y + halfDistance
- return `M${source.x},${source.y} L${source.x},${halfY} ${target.x},${halfY} ${target.x},${target.y}`
- },
- // 展开所有的节点
- expandAllNodes() {
- this.drawChart({
- type: 'all',
- })
- },
- // 将所有节点都折叠
- foldAllNodes() {
- this.drawChart({
- type: 'fold',
- })
- },
- // 点击节点获取节点数据
- nodeClickEvent(e, d) {
- console.log('当前节点的数据:', d)
- if (d.data.level) {
- this.handleChange({ key: d.data.logicId, label: d.data.name })
- }
- },
- },
- }
- </script>
- <style lang="scss" scoped></style>
|