效果图如上 大致效果就是仿照天眼查股权穿透图

曲线会出现节点位置不对(曲线的算法是在不会 技术菜解决不了)   最后刀放到产品脖子他同意用折线代替

在下面已经补充 JSON数据  把请求换成请求本地json  复制下来自己跑 如果不行 加我qq

写的比较乱 有我没写清楚的地方  加我QQ 2557551314

2020.6.8

天眼查 各种d3图均已实现,不在csdn公布 有需要可以加qq,之前自己做的简版的这个图 被发表到个个插件网 恶心到我了。

2019.9.18补

图片导出保存

代码贴在最下方  做了个简版的股权穿透图本地直接能跑起来的 有需要加我

已实现 (拖拽 缩放。 解决元素强制90°横屏touch事件方向问题,pc监听屏幕大小重绘图片,以及SVG图片转img全图下载功能),下面贴代码。

<template><div id="layout"><div id="product_tree"></div><!-- <div id='download' @click="downloadfun()">⬇</div> --><div id="rtbtn" onclick="javascript:history.go(-1);"><img src="../../assets/rtbtn1.png" alt=""></div></div>
</template>
<script>let d3 = require('../../../static/js/d3.min.js');import $ from 'jquery'export default {name: 'tree',data() {let _this = this;return {proCorpid: this.$route.query.corpid,Slide: 0,self: '',screenWidth: document.body.clientWidth,arr: [],tree: document.getElementById('product_tree')};},watch: {screenWidth(val) { //监听屏幕高宽度 重新绘制图片if (!this.timer) {this.screenWidth = valthis.timer = truelet that = thissetTimeout(function() {// console.log(that.screenWidth)let tree = document.getElementById('product_tree')tree.style.width = that.screenWidth + "px";tree.innerHTML = ''that.drawing()that.timer = false}, 500) //延时}}},mounted: function() {var _this = this;_this.self = _this;var tree = document.getElementById('product_tree')function resize() { //设置tree的宽度为屏幕的高度 高度为屏幕的宽度var html = document.getElementsByTagName('html')[0];var width = html.clientWidth;var height = html.clientHeight;var max = width > height ? width : height;var min = width > height ? height : width;tree.style.width = max + "px";tree.style.height = min + "px";tree.style.backgroundColor = "#FFF"}resize();//禁止浏览器body多的部分滚动 若页面内容过长 将不能滑动        tree.addEventListener('touchmove', (e) => {e.preventDefault();e.stopPropagation();}, {passive: false})window.addEventListener("resize", resize)this.drawing()window.onresize = () => { //监听屏幕宽度return (() => {window.screenWidth = document.body.clientWidth_this.screenWidth = window.screenWidth})()};},methods: {downloadfun() { //canvas图片转img下载功能//                 //获取svg内容var _this = this;var html = document.getElementsByTagName('html')[0]; //获取可视区域宽var Bwidth = html.clientWidth;//转换屏幕宽高var Bheight = html.clientHeight;var Bmax = Bwidth > Bheight ? Bwidth : Bheight;var Bmin = Bwidth > Bheight ? Bheight : Bwidth;var canvas = document.createElement("canvas");var g = document.getElementsByTagName('g')[0].getBBox()var svgbox = $('#product_tree svg')var gbox = document.getElementsByClassName('gbox')[0];var x = (g.width / 2 - html.clientWidth / 2) //计算偏移位置var y = 0;g.y < 0 ? y = Math.abs(g.y) : y = 0// gbox.style.transform = "translate(" + x + 'px' + "," + (y-60) + "px" + ")  scale(1)"; //偏移位置gbox.style.transform = "translate(" + x + 'px' + "," + y + "px" + ")  scale(1)"; //偏移位置svgbox.attr('width', g.width)svgbox.attr('height', g.height)var svg = document.getElementById('product_tree').innerHTML;var c = canvas.getContext('2d');//新建Image对象var img = new Image();//svg内容img.src = 'data:image/svg+xml,' + unescape(encodeURIComponent(svg)); //svg内容中可以有中文字符img.src = 'data:image/svg+xml,' + svg; //svg内容中不能有中文字符//图片初始化完成后调用var cwidth = g.width;var imgfile = null;img.onload = function() {//将canvas的宽高设置为图像的宽高canvas.width = cwidth;canvas.height = g.height +60;//canvcas画图片c.fillStyle = "#fff";c.fillRect(0, 0, canvas.width, canvas.height);c.drawImage(img, 0, 30);var a = document.createElement("a");a.download = "fallback";a.herf = canvas.toDataURL("image/png");imgfile = a.herfif(imgfile.length<100){alert('图大')}else{_this.$http.post(_this.BASEURL +'/profund/mail/file',JSON.stringify({'image':imgfile})).then(res=>{console.log(res)}).catch(res=>{})}}//图片转换为base64后 传给后端 发邮件gbox.style.transform = ''svgbox.attr('width', Bmax)svgbox.attr('height', Bmin)},drawing() {var  treeData = {};var _obj = {};var rootName = ''; //根节点的名字var selfthis = this.self;var ajaxurl = this.BASEURL //请求地址var corpid = this.proCorpid;var rootRectWidth = 0; //根节点rect的宽度var downwardLength = 0,upwardLength = 0;var tree = document.getElementById('product_tree')var Slidenum = this.Slidevar treeChart = function(d3Object) {this.d3 = d3Object;this.directions = ['upward', 'downward'];};treeChart.prototype.drawChart = function() { var newTree = {}var self = this;selfthis.$http.post(ajaxurl + 'profund/familysearch', JSON.stringify({"companyType": 0,"corpid": corpid})).then(response => {var res=response.data;if (res.status === 'success') {treeData = JSON.parse(JSON.stringify(res.data))       console.log(treeData)rootName = res.data.downward.name; //获取根节点名称rootRectWidth = rootName.length * 16; //设置第一个节点的宽度//获得upward第一级节点的个数upwardLength = res.data.upward.children.length;//获得downward第一级节点的个数downwardLength = res.data.downward.children.length;self.graphTree(self.getTreeConfig());} else if (res.status === 'error' && res.error === 10328) {alert('暂无数据')history.go(-1)}});};treeChart.prototype.getTreeConfig = function() {var treeConfig = {'margin': {'top': 10,'right': 5,'bottom': 0,'left': 30}}treeConfig.chartWidth = tree.clientWidth;treeConfig.chartHeight = tree.clientHeight;treeConfig.centralHeight = treeConfig.chartHeight / 2;treeConfig.centralWidth = treeConfig.chartWidth / 2;treeConfig.linkLength = 150;treeConfig.duration = 0; //动画时间return treeConfig;};treeChart.prototype.graphTree = function(config) {var self = this;var d3 = this.d3;var linkLength = config.linkLength;var duration = config.duration;var hasChildNodeArr = [];var id = 0;var diagonal = function(obj) { //折线// console.log(obj)var s = obj.source;var t = obj.target;return "M" + (s.x) + "," + s.y + "L" + s.x + "," + (s.y + (t.y - s.y) / 2) + "L" + t.x + "," +(s.y + (t.y - s.y) / 2) + "L" + (t.x) + "," + t.y;}var zoom = d3.behavior.zoom().scaleExtent([0.2, 1.8]).on('zoom', redraw) //缩放var svg = d3.select('#product_tree') //定义svg大小.append('svg').attr("class", "linkG").attr('xmlns', 'http://www.w3.org/2000/svg').attr('width', config.chartWidth + config.margin.right + config.margin.left)// .attr('width',3200).attr('height', config.chartHeight + config.margin.top + config.margin.bottom).on('mousedown', disableRightClick).call(zoom).on('dblclick.zoom', null).on('doubleTap.zoom', null);//                  var treeG = svg.append('g') //添加g元素//                        .attr('transform', 'translate(' + config.margin.left + ',' + config.margin.top + ')');var treeG = svg.append('g') //添加g元素.attr('class', 'gbox').attr('transform', 'translate(' + 0 + ',' + 0 + ') scale(1)');//初始化树节点并更新图表。for (var d = 0; d < this.directions.length; d++) {var direction = this.directions[d];var data = treeData[direction];data.x0 = config.centralWidth;data.y0 = config.centralHeight;data.children.forEach(collapse);update(data, data, treeG);}function update(source, originalData, g) {var direction = originalData['direction'];var forUpward = direction == 'upward';var node_class = direction + 'Node';var link_class = direction + 'Link';var downwardSign = (forUpward) ? -1 : 1; //上下树var nodeColor = (forUpward) ? '#37592b' : '#8b4513';var statusUp = true;var statusDown = true;var nodeSpace = 140;var tree = d3.layout.tree().sort(sortByDate).nodeSize([nodeSpace, 10]);var nodes = tree.nodes(originalData);var links = tree.links(nodes);var offsetX = -config.centralWidth;//过滤调不展示的类型  开始 1-风险P2P关联方// //('类型字典: ; 2-科创板;3-香港企业;4-上市公司; // 5-事业单位;6-保险公司;7-央企控股;8-国企控股;10-新三板;  12-P2P公司 ...待填写',) nodes.forEach(i => { //遍历所有数据i.corptag = i.corptag.filter(item => { //找出数组中要展示的类型其他都过滤掉    返回到原本数组return item == '2' || item == '3' || item == '4' || item == '5' || item == '6' || item == '7' || item =='8' || item == '10' ||item =='12'})})//过滤调不展示的类型 开始nodes.forEach(function(d) {d.y = downwardSign * (d.depth * linkLength) + config.centralHeight;d.x = d.x - offsetX;if (d.grade == 'origin') {d.x = config.centralWidth;d.y += downwardSign * 0; // 上下两树图根节点之间的距离}});// Update the node.var node = g.selectAll('g.' + node_class).data(nodes, function(d) {return d.id || (d.id = ++id);});var nodeEnter = node.enter().append('g').attr('class', node_class).attr('id', function(d) { //给g元素添加id属性return 'g' + d.corpid}).attr('transform', function(d) {return 'translate(' + source.x0 + ',' + source.y0 + ')';}).style('cursor', function(d) {return (d.grade == 'origin') ? '' : (d.children || d._children) ? 'pointer' : '';})// 添加科创等标签开始  // 条件 1 标签两字  2标签自身不能折行 多个标签要换换行 //      //
//                          nodes.map(item => {
//                              return  item.corptag = [7,3,6,12]
//                          }) // 测试时候添加的假数据//动态添加节点d3.selectAll('g').attr('ces', function(d) {if (d && d.corpid) { //判断有corpid的节点let newId = '#g' + d.corpidlet arr = d.corptaglet glist = d3.select(newId)//因tree形会绘制两次 //声明的全局遍历 判断之前是否同id添加过 如果是false就添加 添加完以后改为true 二次渲染不会再进来if (!_obj[d.corpid]) {_obj[d.corpid] = true;setTimeout(() => {for (let i = 0; i < arr.length; i++) { //根据数据量去添加对于元素glist.append('rect').attr('class', 'itembox').attr('width', 26).attr('height', 12).style('fill', colorget(arr[i])) //动态设置颜色.style('x', getX(i)) //动态设置x.style('y', getY(i, forUpward, arr)) //动态设置Y.attr('rx', 2)glist.append('text').attr('x', arr[i] == 10 ? getX(i) + 1.5 : getX(i) + 5).attr('y', getY(i, forUpward, arr) + 9).text(getName(arr[i])).style('font-size', '7').style('fill', textColor(arr[i])).style('letter-spacing', '1px')}})}}})//('类型标签: 1-风险P2P关联方 ; 2-科创板;3-香港企业;4-上市公司; // 5-事业单位;6-保险公司;7-央企控股;8-国企控股;10-新三板;...待填写',) //标签方法function textColor(num) { //标签文字色号num = Number.parseInt(num)var a = ''switch (num) {case 2:a = '#2954A3' //科创breakcase 3:a = '#F26A3A' //香港breakcase 4:a = '#5AA9DE' //上市breakcase 5:a = '#88B764' //事业breakcase 6:a = '#815BDE' //保险breakcase 7:a = '#33DA9F' //央企breakcase 8:a = '#F0B822' //国企breakcase 10:a = '#F022A2' //新三板breakcase 12:a = '#AA2929'//p2p}return a}function getName(num) { //标签文本名字num = Number.parseInt(num)var a = ''switch (num) {case 2:a = '科创' //科创breakcase 3:a = '香港' //香港breakcase 4:a = '上市' //上市breakcase 5:a = '事业' //事业breakcase 6:a = '保险' //保险breakcase 7:a = '央企' //央企breakcase 8:a = '国企' //国企breakcase 10:a = '新三板' //新三板breakcase 12 :a = 'P2P'}return a}function getY(i, forUpward, listlength) { // 数组下标 方向 以及数组let num = 0;let a = 0;if (listlength) {a = listlength.length //获取长度} else {a = 0}if (forUpward) { //上if (i < 4) {num = -15} else {num = 0}} else { //下 if (a > 4) { //down时候 长度小于4的时候全部-30位置的yif (i < 4) { //大于4的时候num = -45} else {num = -30}} else {num = -30}}return num}function getX(i) { //X位置if (i == 0 || i == 4) {i = -58} else if (i == 1 || i == 5) {i = -28} else if (i == 2 || i == 6) {i = 2} else if (i == 3 || i == 7) {i = 32}return i}function colorget(num) { //颜色库num = Number.parseInt(num)var a = ''switch (num) {case 2:a = '#E9F3FF' //科创breakcase 3:a = '#FEECE6' //香港breakcase 4:a = '#DCF3FF' //上市breakcase 5:a = '#EBFFDC' //事业breakcase 6:a = '#EBE2FF' //保险breakcase 7:a = '#D6FFF1' //央企breakcase 8:a = '#FFF2CC' //国企breakcase 10:a = '#FFD9F1' //新三板breakcase 12:a = '#FFC4C4' //p2p}return a}// 添加标签结束function addHeight(d) { //添加位置距离整数 if (d.corptag.length > 0 && d.corptag.length <= 4) {return 15} else if (d.corptag.length > 4) {return 30} else {return 0}}function deviation(d) { //矩形以及元素domn方向y轴改变let num = 0;if (forUpward) {num = 0;} else {if (d.corptag.length > 4) {num = -30} else if (d.corptag.length <= 4 && d.corptag.length > 0) {num = -15} else {num = 0}}return num}function transformY(d) { //up方向元素偏移let num = 0;if (!forUpward) { //down方向时候不动num = 0;} else {if (d.corptag.length > 0 && d.corptag.length <= 4) {num = 15} else if (d.corptag.length > 4) {num = 30} else {num = 0}}return 'translateY(' + num + 'px' + ')'}///开始设置节点 nodeEnter.append("svg:rect").attr("x", function(d) {return (d.grade == 'origin') ? (-rootRectWidth / 2) : -60;}).attr("y", (d) => {return (d.grade == 'origin') ? -20 : forUpward ? -20 : deviation(d) + -20; //有标签时候 down方向的矩形y轴偏移}).attr("width", (d) => {return (d.grade == 'origin') ? rootRectWidth : 120;}).attr("height", (d) => {return (d.grade == 'origin') ? "40" : (d.type == '2') ? 40 : 50 + addHeight(d) //设置节点高度}).attr("rx", 5) //圆角.style("stroke", (d) => {return (d.grade == 'origin') ? "rgb(233,233,233)" : "rgb(230,230,230)";}).style('stroke-width', "1.2").style('fill', (d) => {return (d.grade == 'origin') ? "rgb(83,99,187)" : (d.type == '2') ? "rgb(230,234,248)" : "#FFF";})nodeEnter.append('circle').attr('r', 1e-6)nodeEnter.append("text") //上面一层文字.attr("class", "linkname").attr("x", function(d) {return (d.grade == 'origin') ? '0' : "-55";}).attr('dy', function(d) {return (d.grade == 'origin') ? '.35em' : forUpward ? -5 : -5;}).attr("text-anchor", function(d) {return (d.grade == 'origin') ? 'middle' : "start";}).text(function(d) {if (d.grade == 'origin') {// return ((forUpward) ? '根节点TOP' : '根节点Bottom');return rootName;}if (d.repeated) {// console.log(d.repeated)return '[Recurring] ' + d.name;}return (d.name.length > 10) ? d.name.substr(0, 10) : d.name;}).style('cursor', "pointer").style({'fill-opacity': 1e-6,'fill': function(d) {return (d.grade == 'origin') ? '#fff' : getcolor(d);},'font-size': function(d) {return (d.grade == 'origin') ? 14 : 11;}}).style("letter-spacing", (d) => {return (d.grade == 'origin') ? "1px" : '0'}).style('transform', transformY) //up方向偏移方法.on('click', routeType)nodeEnter.append("text") //中间一层 上一层的折行.attr("class", "linkname").attr("x", "-55").attr("dy", function(d) {return (d.grade == 'origin') ? '.35em' : forUpward ? (d.type != 2) ? "8" : "0" : '8';}).attr("text-anchor", function() {return (d.grade == 'origin') ? 'middle' : "start";}).text(function(d) {return (d.grade == 'origin') ? '' : d.name.length > 17 ? d.name.substr(10, 7) + '...' : d.name.substr(10,7);}).style({// 'fill': "#337ab7",'font-size': function(d) {return (d.grade == 'origin') ? 14 : 11;},'fill': function(d) {return (d.grade == 'origin') ? '#fff' : getcolor(d);},'cursor': "pointer"}).style('transform', transformY) //up方向偏移方法.on('click', routeType) //路由跳转nodeEnter.append("text") //认缴金额一层.attr("x", "-55").attr("dy", function(d) {return (d.grade == 'origin') ? '.35em' : forUpward ? ((d.type == 2) ? "10" : "24") : '23';}).attr("text-anchor", "start").attr("class", "linkname").style("fill", "#000").style('font-size', 10).text(function(d) {var str = (d.grade == 'origin') ? '' : (d.amount != 0 && d.amount != null) ? "认缴金额:" + d.amount + "万元" :"认缴金额:未公开"; //金额return (str.length > 14) ? str.substr(0, 14) + ".." : str;}).style('transform', transformY) //up方向偏移方法nodeEnter.append("text") //股比.attr("x", "10").attr("dy", function(d) {return (d.grade == 'origin') ? '.35em' : forUpward ? ((d.type == 2) ? "32" : "42") : deviation(d) + -23;}).attr("text-anchor", "start").attr("class", "linkname").style("fill", "rgb(0,132,255)").style('font-size', 10).text(function(d) {return (d.grade == 'origin') ? "" : (d.proportion) ? d.proportion + '%' : ''; //股比}).style('transform', transformY) //up方向偏移方法 // 原有节点更新到新位置var nodeUpdate = node.transition().duration(duration).attr('transform', function(d) {return 'translate(' + d.x + ',' + d.y + ')';});nodeUpdate.select('circle').attr('r', function(d) {return (d.grade == 'origin') ? 0 : (d.number > 0) ? 6 : 0;}).attr('cy', function(d) {return (d.grade == 'origin') ? -20 : (forUpward) ? -28 : 38;}).style('fill', function(d) {return d.number > 0 ? "rgb(83,99,187)" : "";})//代表是否展开的+-号nodeEnter.append("svg:text").attr("class", "isExpand").attr("x", "0").attr("dy", function(d) {return forUpward ? -22 : 44;}).attr("text-anchor", "middle").style("fill", "#fff").style('font-size', '18px').text(function(d) {if (d.grade == 'origin') {return '';}return d.number > 0 ? "+" : "";}).on('click', click)nodeUpdate.select('text').style('fill-opacity', 1)var nodeExit = node.exit().transition().duration(duration).attr('transform', function(d) {return 'translate(' + source.x + ',' + source.y + ')';}).remove();nodeExit.select('circle').attr('r', 1e-6)nodeExit.select('text').style('fill-opacity', 1e-6);var link = g.selectAll('path.' + link_class).data(links, function(d) {return d.target.id;}).attr('fill', 'none')//******************************************私募管理人标签 start******************************************////提示框var tsk = nodeEnter.append("svg:rect").attr("x", -64).attr("y", function(d) {return forUpward ? -42 : -42 + deviation(d);}).attr('rx', 2).attr('ry', 2).attr("width", function(d) {if (d.name == 'origin') {return 0} else {return (d.shareholdertype == 'GP') ? "55" : d.corptype == 1 ? '48' : d.prodid ? '40' : '0' //私募管理人标签}}).attr("height", 15).style("fill", function(d) {return (d.shareholdertype == 'GP') ? "#0073ff" : d.corptype == 1 ? '#ffbc00' : d.prodid ? '#2ca111' : ''})//三角形nodeEnter.append("svg:path").attr("fill", (d) => {return (d.shareholdertype == 'GP') ? "#0073ff" : d.corptype == 1 ? '#ffbc00' : d.prodid ? '#2ca111' : ''}).attr("d", function(d) {if (d.name == 'origin') {return ""} else {return (d.shareholdertype == 'GP' || d.corptype == 1 || d.prodid) ? "M-53 -20 L-60 -30 L-46 -30 Z" : ""; //私募管理人标签}}).style('transform', (d) => { //为down时候 看是否存在标签 更改三角定位 使用translatey做y轴偏移let num = 0;if (forUpward) {num = 0;} else {if (d.corptag.length > 0 && d.corptag.length <= 4) {num = -15} else if (d.corptag.length > 4) {num = -30} else {num = 0}}return 'translateY(' + num + 'px' + ')'})nodeEnter.append("svg:text") //三角形中的文字.attr("x", -60).attr("dy", function(d) {return forUpward ? "-32" : -32 + deviation(d);}).attr("text-anchor", "start").style("fill", "#fff").style("font-size", 7).style('letter-spacing', 1).text(function(d) {// console.log(d)return (d.shareholdertype == 'GP') ? "本基金管理人" : d.corptype == 1 ? '私募管理人' : d.prodid ? '私募产品' : ''});//******************************************私募管理人标签 end******************************************//link.enter().insert('path', 'g').attr('class', link_class).attr('d', function(d) {var o = {x: source.x0,y: source.y0,};return diagonal({source: o,target: o,});}).attr("id", function(d, i) {return "mypath" + i;}).attr('fill', 'none').attr('stroke', 'rgb(51, 51, 51)')link.transition().duration(duration).attr('d', diagonal)link.exit().transition().duration(duration).attr('d', function(d) {var o = {x: source.x0,y: source.y0,};return diagonal({source: o,target: o,});}).remove();nodes.forEach(function(d) {d.x0 = d.x;d.y0 = d.y;});function routeType(d) { //路由跳转 //'产品类型:1-私募基金;2-基金专户;3-证券公司资管计划;4-期货公司资管计划;5-信托计划;6-保险公司资管计划;7-银行理财计划;8-券商直投基金;9-资产支持专项计划(ABS);10-公募基金;',// 机构类型字典 '1-私募管理人;2-期货公司;3-证券公司;4-基金子公司;5-信托公司;6-银行;7-公募基金公司;8-上市公司;9-新三板上市公司;10-律师事务所;11-会计师事务所;12-支付机构;99-其他机构;', console.log(window.location.href)// d为点击的当前元素 if (d.corpid && d.corptype == '1') {window.location.href = '/ManagersDetails' + '?corpid=' + d.corpidreturn false} else if (d.prodid) {window.location.href = '/ProBaseInfo' + '?prodid=' + d.prodidreturn false} else {return false}}function getcolor(d) { //设置跳转颜色区分 let Color = ''if (d.corpid && d.corptype == '1') {Color = '#0066cc'} else if (d.prodid) {Color = '#0066cc'} else {Color = '#333333'}return Color}function getNode(type, id) {selfthis.$http.post(ajaxurl + 'profund/familysearch', JSON.stringify(comment)).then(response => {var res = response.data;if (res.status === 'success') {if (type == 1) {mynodes = res.data.upward} else if (type == -1) {mynodes = res.data.downward}}})return mynodes;}function click(d) {var companyType //请求参数if (forUpward) { //定义请求参数的值 1 = 股东      -1 = 对外投资companyType = 1; //参数类型_obj = {}//重新渲染前 清空 判断标签的条件 } else {companyType = -1; //参数类型}if (d.children) {d._children = d.children;d.children = null;            update(d, originalData, g); //重新渲染数据d3.select(this).text("+").style({'font-weight': '400','font-size': '18px',})} else {d.children = d._children;d._children = null;selfthis.$http.post(ajaxurl + 'profund/familysearch', JSON.stringify({'companyType': companyType,'corpid': d.corpid})).then(response => {var res = response.data;if (res.status === 'success') {if (companyType == 1) {d.children = res.data.upward.children;} else if (companyType == -1) {d.children = res.data.downward.children;}update(d, originalData, g); //重新渲染数据d3.select(this).text("-").style({'font-weight': '600','font-size': '23px'})// expand all if it's the first nodeif (d.name == 'origin') {d.children.forEach(expand);}}})}}}function expand(d) {if (d._children) {d.children = d._children;d.children.forEach(expand);d._children = null;}}function collapse(d) {if (d.children && d.children.length != 0) {d._children = d.children;d._children.forEach(collapse);d.children = null;hasChildNodeArr.push(d);}}function redraw() {//强制横屏后 手机端出现touch事件方向 //错误问题 以及ios 安卓兼容性问题//根据浏览器内核判断手机和pc 重新计算方向 顺时针九十度x,y规则 a[0] = b[1]  a[1] = -b[0]var html = document.getElementsByTagName('html')[0];var width = html.clientWidth;var height = html.clientHeight;var a = []var u = navigator.userAgent;var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端if (isAndroid) {a = d3.event.translate; //是安卓} else if (isiOS) {if (window.orientation == 90 || window.orientation == -90) { //判断屏幕方向// console.log("横屏")a = d3.event.translate;} else {var b = d3.event.translate;a[0] = b[1]a[1] = -b[0]}} else { //pc端if (width < height) {var b = d3.event.translate;a[0] = b[1]a[1] = -b[0]} else {a = d3.event.translate;}}treeG.attr('transform', 'translate(' + a + ')' +' scale(' + d3.event.scale + ')');}function disableRightClick() {// stop zoomif (d3.event.button == 2) {console.log('No right click allowed');d3.event.stopImmediatePropagation();}}function sortByDate(a, b) {var aNum = a.name.substr(a.name.lastIndexOf('(') + 1, 4);var bNum = b.name.substr(b.name.lastIndexOf('(') + 1, 4);return d3.ascending(aNum, bNum) ||d3.ascending(a.name, b.name) ||d3.ascending(a.id, b.id);}};var d3GenerationChart = new treeChart(d3);d3GenerationChart.drawChart();}}}
</script><style src="../../css/producttree.css" scoped="scoped"></style>

下面贴css

#product_tree {touch-action: none;z-index: 999;}#rtbtn {position: fixed;width: 25px;height: 25px;top: 20px;border-radius: 4px;box-sizing: content-box;background: #fff;border: 1px solid rgb(83, 99, 187);z-index: 9999;text-align: center;right: 30px;
}#rtbtn img {width: 26px;
}#download {position: fixed;width: 25px;height: 25px;top: 20px;border-radius: 4px;background: #fff;border: 1px solid rgb(83, 99, 187);z-index: 9999;text-align: center;right: 80px;
}@media screen and (orientation:portrait) {/*屏幕旋转90*/#product_tree {transform-origin: 0 0;transform: rotateZ(90deg) translateY(-100%);}
}#product_tree>.centralText {font: 23spx sans-serif;fill: #222;
}#product_tree>.downwardNode text,
#product_tree>.upwardNode text {font: 15px sans-serif;
}

json数据格式

{"data": {"downward": {"children": [{"number": 0,"amount": 0.0000,"proportion": null,"corpid": 9510033851,"corptype": 95,"name": "璞盈(上海)资产管理合伙企业(有限合伙)","prodid": null,"corptag": []}],"grade": "origin","name": "上海璞盈投资管理有限公司","corptag": [],"direction": "downward"},"upward": {"children": [{"number": 0,"amount": 300.0000,"proportion": 30.00,"corpid": null,"corptype": null,"name": "陈其平","shareholdertype": "GENERAL","prodid": null,"type": "2","corptag": []},{"number": 0,"amount": 600.0000,"proportion": 60.00,"corpid": null,"corptype": null,"name": "杨淋","shareholdertype": "GENERAL","prodid": null,"type": "2","corptag": []},{"number": 0,"amount": 100.0000,"proportion": 10.00,"corpid": null,"corptype": null,"name": "刘俊伟","shareholdertype": "GENERAL","prodid": null,"type": "2","corptag": []}],"grade": "origin","name": "上海璞盈投资管理有限公司","corptag": [],"direction": "upward"}},"status": "success"
}

此处贴下载方法 2019.9.18更

const down = document.getElementById('downLond');down.onclick = function(){var _this = this;var html = document.getElementsByTagName('html')[0]; //获取可视区域宽var g = document.getElementsByTagName('g')[0].getBBox()var gbox = document.getElementsByClassName('gbox')[0];var x = -g.x;//计算偏移位置var y = -g.y;// g.y < 0 ? y = Math.abs(g.y) : y = 0// gbox.style.transform = "translate(" + x + 'px' + "," + (y-60) + "px" + ")  scale(1)"; //偏移位置gbox.style.transform = "translate(" + x + 'px' + "," + y + "px" + ")  scale(1)"; //偏移位置var svgbox = $('#box svg')var boxwidth = svgbox.width;var boxheight = svgbox.height;svgbox.attr('width', g.width)svgbox.attr('height', g.height)var canvas = document.createElement("canvas");var c = canvas.getContext('2d');//新建Image对象//svg内容var svg = document.getElementById('box').innerHTML;var img = new Image();img.src = 'data:image/svg+xml,' + unescape(encodeURIComponent(svg));//svg内容中可以有中文字符img.src = 'data:image/svg+xml,' + svg;//svg内容中不能有中文字符img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(svg)));//svg内容中可以有中文字符//图片初始化完成后调用img.onload = function() {//将canvas的宽高设置为图像的宽高canvas.width = img.width;canvas.height = img.height+60;c.fillStyle = "#fff";c.fillRect(0, 0, canvas.width, canvas.height);c.drawImage(img, 0, 30);//canvas画图片var a = document.createElement("a");a.download = "png";a.href= canvas.toDataURL("image/png");a.click();}//图片转换为base64后 传给后端 发邮件  gbox.style.transform = ''svgbox.attr('width',boxwidth)svgbox.attr('height',boxheight)}

写的不好的地方希望大家指点

评论的 看到我会回复

D3 天眼查 股权穿透 股权结构相关推荐

  1. D3 天眼查 股权穿透 股权结构,默认第一行,异步添加,加减号居中,拖拽,缩放, hover。

    因为公司项目需求,在以下相关博客的的基础上,进行了修改. ​​​​​​D3 天眼查 股权穿透 股权结构 1.鼠标经过路径高亮. 2. 加减号优化,很多文章都是直接text标签渲染 "+&qu ...

  2. D3 天眼查 股权结构图

    效果大致就是上图 tianyancha上面 该效果叫股权结构  图上信息属于公示信息 不存在泄密 暂时不考虑兼容性和下载  旋转等问题.如有这些问题 可以查看我上一篇股权穿透图 有对应解决方案. 本文 ...

  3. 仿企查查、天眼查股权穿透d3

    企业图谱做出来了,接下来仿企查查写个股权穿透的图谱 企查查股权穿透 自己的 首先使用的方法以及生成图的方法 跟企业图谱类似 也是用的d3官方demo给出的生成双向树的方法,不过版本是d3.v3 相比企 ...

  4. 前端vue uni-app仿企查查、天眼查关联投资机构 股权结构 树形结构 控股结构

    快速实现vue uni-app前端仿企查查.天眼查关联投资机构 股权结构 树形结构 控股结构, 下载请访问uni-app插件市场:https://ext.dcloud.net.cn/plugin?id ...

  5. 【vue d3 v4】vue2结合d3实现类似企查查的股权穿透图、股权结构图

    前言 vue3 框架中使用vue2代码结合d3完成股权穿透图和股权结构图(h5) (没错听上去很违规,但我懒得把代码从vue2改成vue3了,所以是在vue3框架里用vue2写法完成的) 最终效果: ...

  6. D3 企业关系图谱 企业构成图谱 股权穿透图 股权结构图 关联方认定图

    前言:之前说做了项目,这个项目黄了,公司跑路了,代码就拿出来分享,主要就是实现各种类似企查查的各种图谱,欢迎交流.目前已大致实现了: D3 企业关系图谱 企业构成图谱 股权穿透图 股权结构图 关联方认 ...

  7. 使用d3实现类似脑图,股权穿透图,关系图谱

    前言 最近工作需要完成一个股权穿透图,找了好多文档发现都不满足需求,最终选择d3.js来实现,包含子集的收缩展开,交互以及其他功能.之前由于没做过类似关系图以及不了解d3,踩了很多坑,我会尽可能将代码 ...

  8. d3.js实现股权穿透图(vue+d3.js)

    d3.js实现股权穿透图 业务需求 1.实现的效果图 2.安装依赖 3.全部代码(复制粘贴即可实现) 参考git地址 业务需求 前段时间写过一篇使用relation-graph插件实现的股权穿透图效果 ...

  9. d3 企业图谱 仿天眼查 企查查

    最近接到一个需求,终端要加入企业图谱的功能.能无线穿透下去,之前写过一个类似树形图但是节点长度没有自适应(如下图),样式也不够好看,产品提出做一个类似企查查那种的企业图谱,能更直观的展示企业信息,无奈 ...

最新文章

  1. Ubuntu查看硬件详细信息
  2. AI Time | 论道数据共享开放与隐私保护
  3. OpenGL Tessellation细分曲面的实例
  4. 砂.随笔.二十.微笑
  5. matlab中float类型的_Java局部变量类型推断(Var类型)的26条细则
  6. I2C 协议分析和学习
  7. 三维旋转矩阵_旋转之一 - 复数与2D旋转
  8. git多系统协作时换行符问题
  9. layui中折叠面板的使用
  10. 微信小程序 eventChannel在页面间传参
  11. [BZOJ 4010] 菜肴制作
  12. 计算机维护费入什么会计科目,金税盘技术维护费计入什么科目_增值税
  13. 易康(eCognition)对象几何特征--1:几何(Geometry)_范围(Extent)
  14. php如何验证银行卡号,PHP效验银行卡卡号
  15. IJCAI2022推荐系统论文集锦
  16. 游戏角色写实头发制作
  17. 微信公众号添加word文档附件教程_公众号添加Excel、PDF、PPT等附件教程
  18. 图卷积神经网络GCN中的关键公式推导---干货
  19. 微信商城开发的主要特点是什么
  20. 元宇宙岗位薪资排行榜,出炉!

热门文章

  1. 微程序控制器的基本原理
  2. 如何用python请求接口
  3. oracle 报12560,UNIX系统中Oracle报TNS-12560错误的解决思路
  4. 04以太坊测试网(Testnets)
  5. 如何做好检测报告的质量控制?-LIMS2
  6. php发布编辑删除功能,php实现添加修改删除
  7. 【运用flex制作携程界面练习笔记】
  8. Qt绘制旋转的轮播图
  9. (IROS 2022) 基于事件相机的单目视觉惯性里程计 / Event-based Monocular Visual Inertial Odometry
  10. 嵌入式-ARM-学习总结(7):按键与中断