AntV G6自定义树状图TreeGraph

只是为了记录下自己写的G6组件成果

G6去除生成图的动画效果animate

 const graph = new G6.TreeGraph({animate: false, // 切换布局时是否使用动画过度})

G6拓扑图刷新页面按钮事件(刷新按钮根据页面变化展示不同的图片)

    <!-- 复位按钮 --><div class="reset-fitView"id="reset-button"><img :src="resetViewUrl"style="margin: 4px;"></div>// 设置复原按钮图片默认值
export default {data () {return {resetViewUrl: require('./img/original.svg'), // 复位按钮根据画布调整改变展示图片 }},

以下这段代码结合下面,标题“还有各种鼠标事件(G6拓扑图缩放事件等)”里的,根据数据创建树状图节createNode () 方法里的页面缩放操作,可以官方文档搜viewportchange属性了解页面事件

  // 监听画布缩放let originalView = graph.getZoom()let number = graph.getZoom()graph.on('viewportchange', e => {if (e.action == 'translate') { // 画布被拖动this.resetViewUrl = require('./img/change.svg')}if (e.action !== 'zoom') return; // 画布未被缩放const currentZoom = graph.getZoom();number = currentZoom;this.resetViewUrl = require('./img/change.svg')if (originalView == number) {this.resetViewUrl = require('./img/original.svg')}});// 画布里数据展示复位var resetView = document.getElementById('reset-button')resetView.onclick = function () {graph.render();graph.fitView();};

还有各种鼠标事件(G6拓扑图缩放事件等)

<template><div class="topology-diagram"><div id="containerBox"style="background: #F7F8FA;border-radius: 4px;"></div><!-- 判断是否为预览不展示 --><div v-if="show"class="img-annotation"><div class="annotation-icon1"></div><span class="annotation-text1">允许出入</span><div class="annotation-icon2"></div><span class="annotation-text2">无权限</span><img class="annotation-icon3"src="./img/disable.svg" /><span class="annotation-text3">禁止出入</span></div><!-- 判断是否为预览展示位置不一样 --><div class="operation-button":style="show ? 'margin-top: -48px;margin-left: 262px;':'position: absolute;right: 12px;top: 380px;'"><img src="./img/zoom-out-button.svg"style="margin-left: 16px;margin-top: 11px;"id="zoom-out-button" /><img src="./img/zoom-in-button.svg"style="margin-left: 16px;margin-top: 11px;"id="zoom-in-button" /></div><!-- <div id="minimapBox"style="background: #F7F8FA;margin-top: -100px;width: 100px;height: 100px;"></div> --><drawer :title="title":display.sync="display":inner="true":width="drawerWidth":height="drawerHeight":regionType="regionType":mask="false"></drawer></div>
</template>
<script>
import G6 from '@antv/g6'
import drawer from '@/components/drawer/drawer'
export default {data () {return {title: '',title_id: '',// 用于判断右边浮窗关闭弹出效果drawerHeight: '557px',display: false,drawerWidth: '220px',regionType: -1,// 根据通行点类型展示不同图片、以及不同的鼠标悬浮图标imgPath: '',imgHoverPath: '',imgDisablePath: '',imgNoPermissionPath: '',}},props: {// 宽度topologyMapWidth: {type: String,default: '1121'},// 高度HtopologyMapHeight: {type: String,default: '570'},topologyMapData: { // 拓扑图数据type: Object,default: () => {return {}}},// 判断是否需要鼠标数据、放大缩小点击按钮再左下还是右下、图左下注解是否展示show: {type: Boolean,default: true}},components: {drawer},mounted () {this.customNode()this.createNode()},methods: {// 自定义节点方法customNode () {// 文本超出隐藏 (字段, 最大长度, 字体大小)const fittingString = (str, maxWidth, fontSize) => {const ellipsis = '...';const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];let currentWidth = 0;let res = str;const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and lettersstr.split('').forEach((letter, i) => {if (currentWidth > maxWidth - ellipsisLength) return;if (pattern.test(letter)) {// Chinese charactorscurrentWidth += fontSize;} else {// get the width of single letter according to the fontSizecurrentWidth += G6.Util.getLetterWidth(letter, fontSize);}if (currentWidth > maxWidth - ellipsisLength) {res = `${str.substr(0, i)}${ellipsis}`;}});return res;};// 节点缩放点击事件,根据不同场所展示不同样式const marker = (hasChildren, group, cfg, rect) => {if (hasChildren) {if (cfg.category == 0) {group.addShape('image', {attrs: {x: rect.getBBox().width - 80,y: rect.getBBox().height / 2 - 84.5,cursor: 'pointer',width: 20,height: 20,img: cfg.collapsed ? require('./img/close1.svg') : require('./img/open1.svg'),},name: 'collapse-icon0',modelId: cfg.id,})} if (cfg.category == 1) {group.addShape('image', {attrs: {x: rect.getBBox().width - 80,y: rect.getBBox().height / 2 - 84.5,cursor: 'pointer',width: 20,height: 20,img: cfg.collapsed ? require('./img/close2.svg') : require('./img/open2.svg'),},name: 'collapse-icon1',modelId: cfg.id,})} if (cfg.category == 2) {group.addShape('image', {attrs: {x: rect.getBBox().width - 80,y: rect.getBBox().height / 2 - 84.5,cursor: 'pointer',width: 20,height: 20,img: cfg.collapsed ? require('./img/close3.svg') : require('./img/open3.svg'),},name: 'collapse-icon2',modelId: cfg.id,})} if (cfg.category == 3) {group.addShape('image', {attrs: {x: rect.getBBox().width - 80,y: rect.getBBox().height / 2 - 84.5,cursor: 'pointer',width: 20,height: 20,img: cfg.collapsed ? require('./img/close4.svg') : require('./img/open4.svg'),},name: 'collapse-icon3',modelId: cfg.id,})}}}const _this = thisG6.registerNode('tree-node',{drawShape: function drawShape (cfg, group) {const rect = group.addShape('rect', {attrs: {fill: '#E9EBF5',stroke: '#E9EBF5',cursor: 'pointer',x: 0,y: 0,width: 1,height: 1,radius: 8},name: 'rect-shape',});let textX = -24let textY = 0let iconLength = cfg.units ? cfg.units.length : 0 // 节点里的图标个数 // let iconLength = cfg.iconLength// const content = cfg.name;let number = 10 // 两个图标换行let textArray = []for (let i = 0; i < iconLength; i++) {if (i != 0) {if ((i + 1) % number === 1) {textY = textY + 50 + 17textX = -24} else if ((i + 1) % number != 1) {textX = textX + 41 + 30}}const content = cfg.units[i].name;textArray[i] = group.addShape('text', {attrs: {text: fittingString(content, 66, 11),x: textX,y: textY,cursor: 'pointer',textAlign: 'center',textBaseline: 'middle',fill: '#424874',fontSize: 11,fontWeight: 400,fontFamily: 'PingFangSC-Regular, PingFang SC',lineHeight: 17,width: 66},name: 'text-shape' + i,});// 判断门禁状态 .units.permission    出入点权限 0 允许 1 禁止 为空时无权限if (cfg.units[i].permission === '' || cfg.units[i].permission === 1) {textArray[i].attr('fill', '#C3C5D9')continue}console.log('1111111111111111111111!_this.show', !_this.show);if (!_this.show) continue// 判断通行点类型(只判断出入点、电梯厅)unitTypeCode 通行点类型 pass 通行点 elevator 电剃厅textArray[i].on('mouseenter', e => {imgArray[i].attr('img', cfg.units[i].unitTypeCode === 'pass' ? require('./img/passHover.svg') : require('./img/elevatorHover.svg'))textArray[i].attr('fill', '#6373FF')})textArray[i].on('mouseleave', e => {imgArray[i].attr('img', cfg.units[i].unitTypeCode === 'pass' ? require('./img/pass.svg') : require('./img/elevator.svg'))textArray[i].attr('fill', '#424874')})textArray[i].on('click', e => {// 根据门禁id判断是否重复点击同一个门禁if (_this.title_id !== cfg.id) {_this.display = _this.display ? !_this.display : _this.displaysetTimeout(() => {_this.title = content_this.title_id = cfg.id_this.regionType = cfg.category_this.display = !_this.display}, 500)} else {_this.title = content_this.title_id = cfg.id_this.regionType = cfg.category_this.display = true}})}// 无门禁时let NoIconif (iconLength === 0) {NoIcon = group.addShape('text', {attrs: {text: fittingString('无门禁', 61, 12),x: textX,y: textY,textAlign: 'center',textBaseline: 'middle',fill: '#424874',fontSize: 12,fontWeight: 400,fontFamily: 'PingFangSC-Regular, PingFang SC',lineHeight: 17,width: 61},name: 'text-shape0',});}const text = textArray[0] ? textArray[0] : NoIconconst bbox = text.getBBox();const hasChildren = cfg.children && cfg.children.length > 0;let nodeHeight = iconLength === 0 ? 0 : iconLength % number > 0 ? Math.ceil(iconLength / number) : iconLength / number // 节点根据图标换行相应高度rect.attr({x: -66 / 2 - 20 - 28,y: -24 - 50, // 节点框根据图标上移width: NoIcon ? 250 : nodeHeight === 0 ? ((32 + 51) * (number - 1)) : number > iconLength ? ((32 + 45) * iconLength) : ((32 + 51) * (number - 1)),height: NoIcon ? bbox.height + 120 : number >= iconLength ? bbox.height + 120 : 80 * nodeHeight,});const rectBox = rect.getBBox();let imgX = rectBox.x + 30let imgY = rectBox.y + 30let imgArray = []for (let i = 0; i < iconLength; i++) {if (i != 0) { // 图标移动间隔距离if ((i + 1) % number === 1) {imgY = imgY + 32 + 35imgX = rectBox.x + 32} else if ((i + 1) % number != 1) {imgX = imgX + 32 + 40}}// 判断通行点类型(只判断出入点、电梯厅)unitTypeCode 通行点类型 pass 通行点 elevator 电剃厅imgArray[i] = group.addShape('image', {attrs: {x: imgX,y: imgY,width: 32,height: 32,cursor: 'pointer',img: cfg.units[i].unitTypeCode === 'pass' ? require('./img/pass.svg') : require('./img/elevator.svg'),shadowBlur: 20,// shadowColor: '#C7CBF6',shadowColor: '#C6C9EA'},name: 'image-shape' + i,});textArray[i].attr({x: imgX + 16, // 文字根据图片宽度居中y: imgY + 32 + 12, // 32图片宽度12文字图片间距});// 判断门禁状态 .units.permission    出入点权限 0 允许 1 禁止 为空时无权限if (cfg.units[i].permission === '') {imgArray[i].attr('img', cfg.units[i].unitTypeCode === 'pass' ? require('./img/passNoPermission.svg') : require('./img/elevatorNoPermission.svg'))continue}if (cfg.units[i].permission === 1) {imgArray[i].attr('img', cfg.units[i].unitTypeCode === 'pass' ? require('./img/passDisable.svg') : require('./img/elevatorDisable.svg'))continue}if (!_this.show) continue// const imageBox = group.find((element) => element.get('name') === 'image-shape' + i);imgArray[i].on('mouseenter', e => {imgArray[i].attr('img', cfg.units[i].unitTypeCode === 'pass' ? require('./img/passHover.svg') : require('./img/elevatorHover.svg'))textArray[i].attr('fill', '#6373FF')})imgArray[i].on('mouseleave', e => {imgArray[i].attr('img', cfg.units[i].unitTypeCode === 'pass' ? require('./img/pass.svg') : require('./img/elevator.svg'))textArray[i].attr('fill', '#424874')})imgArray[i].on('click', e => {// 根据门禁id判断是否重复点击同一个门禁if (_this.title_id !== cfg.id) {_this.display = _this.display ? !_this.display : _this.displaysetTimeout(() => {_this.title = cfg.units[i].name_this.title_id = cfg.id_this.regionType = cfg.category_this.display = !_this.display}, 500)} else {_this.title = cfg.units[i].name_this.title_id = cfg.id_this.regionType = cfg.category_this.display = true}})}// 文件头****************************************************************************************// 文件头文字let fileText = cfg.nameconst imageLeft = group.addShape('image', {attrs: {x: rectBox.x + 36,y: rectBox.y - 23.5,width: 36,height: 24,img: require('./img/left.svg'),},name: 'image-left',});const rectFile = group.addShape('rect', {attrs: {x: rectBox.x + 36 + 36,y: rectBox.y - 23,height: 24,width: 36,stroke: '#E9EBF5',fill: '#E9EBF5',},name: 'rect-file',});const imageRight = group.addShape('image', {attrs: {x: rectFile.getBBox().x + rectFile.getBBox().width,y: rectFile.getBBox().y,width: 36,height: 24,img: require('./img/right.svg'),},name: 'image-right',});// 图标不固定要做判断,判断0:园区 1:楼栋 2:楼层 3:办公区*************************let fileIconUrl = require('./img/fileIcon1.svg')if (cfg.category == 0) {fileIconUrl = require('./img/fileIcon1.svg')} if (cfg.category == 1) {fileIconUrl = require('./img/fileIcon2.svg')} if (cfg.category == 2) {fileIconUrl = require('./img/fileIcon3.svg')} if (cfg.category == 3) {fileIconUrl = require('./img/fileIcon4.svg')}const fileIcon = group.addShape('image', {attrs: {x: rectFile.getBBox().x - 8,y: rectFile.getBBox().y + 5,width: 20,height: 20,img: fileIconUrl,},name: 'file-icon',});const textFile = group.addShape('text', {attrs: {text: fileText,x: fileIcon.getBBox().x + 20 + 8,y: fileIcon.getBBox().y + 12,textAlign: 'left',textBaseline: 'middle',fill: '#202340',fontSize: 16,fontWeight: 400,fontFamily: 'PingFangSC-Regular, PingFang SC',lineHeight: 22,},name: 'text-file',});// 文件文字宽度重新渲染文件头样式宽度度rectFile.attr({width: textFile.getBBox().width + fileIcon.getBBox().width + 8,});imageRight.attr({x: rectFile.getBBox().x + rectFile.getBBox().width,y: rectFile.getBBox().y,});// 节点宽度根据文件头宽度来判断let fileWidth = rectFile.getBBox().width + 36 + 36 + 24 + 24if (fileWidth > rectBox.width) {rect.attr({width: fileWidth + 36,});}// 无门禁时,文字定位在节点的中心if (NoIcon) {NoIcon.attr({x: (rect.getBBox().width) / 2 - 36 - 40,});}// 节点后面加号位置,判断0:园区 1:楼栋 2:楼层 3:办公区marker(hasChildren, group, cfg, rect)// 整个节点悬浮时节点+文件头悬浮样式*****************************************************if (_this.show) {rect.on('mouseenter', e => {imageLeft.attr('img', require('./img/leftHover.svg'))imageRight.attr('img', require('./img/rightHover.svg'))rect.attr({stroke: '#DFE0ED',fill: '#DFE0ED',})rectFile.attr({stroke: '#DFE0ED',fill: '#DFE0ED',})})rect.on('mouseleave', e => {imageLeft.attr('img', require('./img/left.svg'))imageRight.attr('img', require('./img/right.svg'))rect.attr({fill: '#E9EBF5',stroke: '#E9EBF5',})rectFile.attr({stroke: '#E9EBF5',fill: '#E9EBF5',})})// 节点整体点击释放样式*********************************************************rect.on('mousedown', e => {imageLeft.attr('img', require('./img/leftSelect.svg'))imageRight.attr('img', require('./img/rightSelect.svg'))rect.attr({fill: '#DEE3FA',stroke: '#DEE3FA',})rectFile.attr({fill: '#DEE3FA',stroke: '#DEE3FA',})})rect.on('mouseup', e => {imageLeft.attr('img', require('./img/leftHover.svg'))imageRight.attr('img', require('./img/rightHover.svg'))rect.attr({stroke: '#DFE0ED',fill: '#DFE0ED',})rectFile.attr({stroke: '#DFE0ED',fill: '#DFE0ED',})})// 节点整体点击事件*********************************************************rect.on('click', e => {_this.regionType = cfg.category // 需判断是0:园区 1:楼栋 2:楼层 3:办公区// 根据节点id判断是否重复点击同一个门禁if (_this.title_id !== cfg.id) {_this.display = _this.display ? !_this.display : _this.displaysetTimeout(() => {_this.title = cfg.name_this.title_id = cfg.id_this.display = !_this.display}, 500)} else {_this.display = true_this.title = cfg.name_this.title_id = cfg.id}})}return rect;},// 节点展开收起点击事件,判断0:园区 1:楼栋 2:楼层 3:办公区setState (name, value, item) {// 四个不同节点点击缩放颜色转换if (name === 'collapse') {const group = item.getContainer();const collapseIcon = group.find((e) => e.get('name') === 'collapse-icon0');if (collapseIcon) {if (!value) {collapseIcon.attr({img: require('./img/open1.svg')});} else {collapseIcon.attr({img: require('./img/close1.svg')});}}const collapseIcon1 = group.find((e) => e.get('name') === 'collapse-icon1');if (collapseIcon1) {if (!value) {collapseIcon1.attr({img: require('./img/open2.svg')});} else {collapseIcon1.attr({img: require('./img/close2.svg')});}}const collapseIcon2 = group.find((e) => e.get('name') === 'collapse-icon2');if (collapseIcon2) {if (!value) {collapseIcon2.attr({img: require('./img/open3.svg')});} else {collapseIcon2.attr({img: require('./img/close3.svg')});}}const collapseIcon3 = group.find((e) => e.get('name') === 'collapse-icon3');if (collapseIcon3) {if (!value) {collapseIcon3.attr({img: require('./img/open4.svg')});} else {collapseIcon3.attr({img: require('./img/close4.svg')});}}}},},'single-node',);},// 根据数据创建树状图节点createNode () {const container = document.getElementById('containerBox');const width = container.scrollWidth - 8;//  const width = this.topologyMapWidth;const height = container.scrollHeight || this.topologyMapHeight;// 实例化 minimap 插件// const minimap = new G6.Minimap({//   container: 'minimapBox',//   size: [100, 100],//   className: 'minimap',//   type: 'default',// });const graph = new G6.TreeGraph({container: 'containerBox',// plugins: [minimap],width,height,modes: {default: ['drag-canvas','zoom-canvas',],},defaultNode: {type: 'tree-node',anchorPoints: [[0, 0.5],[1, 0.5],],},// nodeStateStyles: {//   hover: {//     fill: '#fff',//     stroke: '#fff',//     // shadowBlur: 20,//     // shadowColor: '#5666de',//   }// },defaultEdge: {type: 'flow-line',// type: 'cubic-horizontal'style: {stroke: '#C3C5D9',},},layout: {type: 'compactBox',direction: 'LR',getId: function getId (d) {return d.id;},getHeight: function getHeight () {return 260;},getWidth: function getWidth () {return 260;},getVGap: function getVGap () {return 120;},getHGap: function getHGap () {return 380;},},});// 设置线条样式-------------------------------------------G6.registerEdge('flow-line', {draw (cfg, group) {const startPoint = cfg.startPoint;const endPoint = cfg.endPoint;const { style } = cfg;const shape = group.addShape('path', {attrs: {stroke: style.stroke,endArrow: style.endArrow,// lineWidth: 1,path: [['M', startPoint.x + 22, startPoint.y],['L', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y], // 三分之一处['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y], // 三分之二处['L', endPoint.x, endPoint.y]],},});return shape;},});// 节点缩放点击事件const handleCollapse = (e) => {const target = e.target;const id = target.get('modelId');const item = graph.findById(id);graph.setItemState(item, 'collapse', true); // 数据collapsed默认为true时,第一次点击不触发+变为-,故加上此行,const nodeModel = item.getModel();nodeModel.collapsed = !nodeModel.collapsed;graph.layout();graph.setItemState(item, 'collapse', nodeModel.collapsed);};graph.on('collapse-icon0:click', (e) => {handleCollapse(e);});graph.on('collapse-icon1:click', (e) => {handleCollapse(e);});graph.on('collapse-icon2:click', (e) => {handleCollapse(e);});graph.on('collapse-icon3:click', (e) => {handleCollapse(e);});// graph.on('node:mouseenter', e => {//   graph.setItemState(e.item, 'hover', true);// })// graph.on('node:mouseleave', e => {//   graph.setItemState(e.item, 'hover', false);// });// fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/modeling-methods.json')//   .then((res) => res.json())//   .then((data) => {G6.Util.traverseTree(this.topologyMapData, function (item) {item.id = item._id;});graph.data(this.topologyMapData);graph.render();graph.fitView();// });// 监听画布缩放let number = graph.getZoom()graph.on('viewportchange', e => {if (e.action !== 'zoom') return;const currentZoom = graph.getZoom();number = currentZoom;});// 获取缩小放大按钮var zoomOut = document.getElementById('zoom-out-button');var zoomIn = document.getElementById('zoom-in-button');// 根据目前画布的缩放比例调整缩放比例zoomOut.onclick = function () {number = number - 0.2if (number < 0.2) number = 0.2graph.zoomTo(number, { x: 300, y: 300 });};zoomIn.onclick = function () {number = number + 0.2graph.zoomTo(number, { x: 300, y: 300 });};if (typeof window !== 'undefined')window.onresize = () => {if (!graph || graph.get('destroyed')) return;if (!container || !container.scrollWidth || !container.scrollHeight) return;graph.changeSize(container.scrollWidth, container.scrollHeight);};}}
}
</script>
<style>
.topology-diagram {width: 100%;height: 100%;
}
.topology-diagram .img-annotation {width: 233px;height: 36px;background: rgba(255, 255, 255, 0.9);box-shadow: 0px 0px 4px 0px #e2e3ee;border-radius: 4px;/* margin-top: -48px;margin-left: 12px; */display: inline-block;position: absolute;margin-left: 12px;margin-top: -48px;
}
.topology-diagram .annotation-icon1 {width: 10px;height: 10px;background: #6271f0;border-radius: 2px;margin-top: 13px;margin-left: 12px;display: inline-block;
}
.topology-diagram .annotation-icon2 {width: 10px;height: 10px;background: #c3c5d9;border-radius: 2px;display: inline-block;margin-left: 16px;margin-top: 13px;
}
.topology-diagram .annotation-icon3 {display: inline-block;margin-left: 16px;margin-top: 13px;
}
.topology-diagram .annotation-text1 {width: 48px;height: 17px;font-size: 12px;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #202340;line-height: 17px;margin-top: 9px;margin-left: 5px;
}
.topology-diagram .annotation-text2 {width: 36px;height: 17px;font-size: 12px;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #202340;line-height: 17px;margin-left: 5px;margin-top: 9px;
}
.topology-diagram .annotation-text3 {width: 48px;height: 17px;font-size: 12px;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #202340;line-height: 17px;margin-left: 5px;margin-top: 9px;
}
.topology-diagram .operation-button {width: 76px;height: 36px;background: rgba(255, 255, 255, 0.9);box-shadow: 0px 0px 4px 0px #e2e3ee;border-radius: 4px;display: inline-block;position: absolute;
}
</style>

AntV G6自定义树状图TreeGraph相关推荐

  1. HTML+CSS自定义树状图

    HTML+CSS自定义树状图 主体部分 css部分 主体部分 <div class="test"><ul class="domtree"> ...

  2. vue项目实现G6双向树状图最详细教程

    在项目中使用 NPM 包引入 npm install --save @antv/g6 AntV G6 示例图 初始化数据 点击节点动态加入数据 上代码(vue 文件) <template> ...

  3. 使用 R 和 ggraph 自定义树状图

    首先使用igraph包创建数据集和图形对象. # Libraries library(ggraph) library(igraph) library(tidyverse) theme_set(them ...

  4. Linux 命令之 tree -- 以树状图列出目录的内容/查看目录内容

    文章目录 一.命令介绍 二.常用选项 三.命令示例 (一)按树形结构显示当前目录下的内容 (二)按树状图显示当前目录下的所有目录名称而非文件 (三)列出指定目录下的第一层级的文件和目录名称 (四)不显 ...

  5. html树状图右侧_treeview-树形菜单js组件编写及应用

    简要介绍: 之前手头的一个项目需要去做一个左侧的树形菜单,右侧则是一个整体的iframe,从而构成一个整体的网站.一开始是打算用bootstrap的tree-view插件,直接把菜单的数据传过去就好了 ...

  6. d3.js(v5.7)树状图

    一.新建画布 二.数据处理 三.绘制连接线 图示: 四.绘制节点.文字 图示: 五.总结 path元素:其实就是定义了绘图的坐标点,从哪开始,移动到哪,怎样移动(命令) 具体可百度(或许以后我会总结一 ...

  7. json树状图可视化_12个流行的Python数据可视化库总结

    总结了10个不同领域的 Python 数据可视化库,有常用的,也有比较小众的. 1. matplotlib matplotlib是Python数据可视化库的OG.尽管它已有十多年的历史,但仍然是Pyt ...

  8. 如何在 LaTeX 中画一个树状图(使用tikz和tikz-qtree包中的宏绘制树、森林、二叉树)

    简单介绍 在计算机相关的文章中,树状图是最常见的几种图之一.树状图经常被用来用来演示结构.层次.算法等内容.而二叉树是最基础的树状图之一,掌握二叉树的画法就可以用图像展示一些算法或者数据结构了. 在 ...

  9. html树状图在线画板,五款在线思维导图工具,总有一款适合你

    原标题:五款在线思维导图工具,总有一款适合你 思维导图是表达发散性思维的有效图形思维工具,通过一些主要的关键词,用非线性的方式展现出来.思维导图的真正用处不是让你能直接获得多少多少的好处,它更多的,还 ...

最新文章

  1. deepLink iOS 应用到自己APP 记录
  2. LiveVideoStackCon 音视频技术大会 2022 上海站日程发布啦!
  3. numpy 创建加一行_Python数据分析快速入门--NumPy amp; Pandas
  4. (转)Windows 批处理实现 定时打开IE 延时一段时间后 关闭IE
  5. 59 MM配置-后勤发票校验-维护税代码缺省值
  6. U盘安装CentOS 7错误 /dev/root does not exist, could not
  7. php apache 404,如何从PHP显示默认的Apache 404
  8. mysql在window的使用记录
  9. ActiveMQ Windows部署
  10. HTML怎么写入形状,css3写各种形状(收集篇...)
  11. windows下调用外部exe程序 SHELLEXECUTEINFO
  12. python pyhook_python使用pyHook.HookManager()返回来的event中,event.Time怎么转换成为datetime形式?...
  13. 【百度AI图像识别】LOGO帝来袭~ 个体再小、LOGO不能少
  14. shiyou的数值分析作业
  15. 苹果试玩换个新id行不_苹果试玩换ID可以重复任务吗
  16. 钢琴家以前是学计算机的,奇特的钢琴家——裘元朴
  17. 带顶点动画的护盾效果——UnityShader学习笔记
  18. 台式机电源相关参数说明
  19. 工业相机各种参数计算方法
  20. 【python练习,6.15】(霍兰德人格分析雷达图等)

热门文章

  1. 介绍几个移动广告平台
  2. 做一个保护星球小游戏
  3. SAP ABAP 一个有用的程序正确性辅助工具,Checkpoint group 的使用方法介绍试读版
  4. 软件测试面试python一般会问什么问题_软件测试面试一定会问到的面试问题
  5. python 学习笔记(二)
  6. 计算机房颁奖词,期末考试表彰颁奖词.doc
  7. 四千GB电脑技术高清视频教程和23万套各类源码模板
  8. win7左ctrl和左alt键互换
  9. 用HTML和CSS实现搜索框
  10. 成都榆熙:拼多多商家们都怎么应对店铺标签乱了这个情况?