<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        如何用D3.js實現拓撲圖

        來源:懂視網 責編:小采 時間:2020-11-27 19:33:54
        文檔

        如何用D3.js實現拓撲圖

        如何用D3.js實現拓撲圖:這篇文章主要介紹了關于如何用D3.js實現拓撲圖,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下最近寫項目需要畫出應用程序調用鏈的網路拓撲圖,完全自己寫需要花費些時間,那么首先想到的是echarts,但echarts的自定義寫法寫起來非常麻煩,而
        推薦度:
        導讀如何用D3.js實現拓撲圖:這篇文章主要介紹了關于如何用D3.js實現拓撲圖,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下最近寫項目需要畫出應用程序調用鏈的網路拓撲圖,完全自己寫需要花費些時間,那么首先想到的是echarts,但echarts的自定義寫法寫起來非常麻煩,而
        這篇文章主要介紹了關于如何用D3.js實現拓撲圖,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

        最近寫項目需要畫出應用程序調用鏈的網路拓撲圖,完全自己寫需要花費些時間,那么首先想到的是echarts,但echarts的自定義寫法寫起來非常麻煩,而且它的文檔都是基于配置說明的,對于自定義開發不太方便,嘗試后果斷放棄,改用D3.js,自己完全可控。

        我們先看看效果

        3420275523-5b37148dc6036_articlex[1].png

        我把代碼分享下,供和我一樣剛接觸D3的同學參考,不對的地方歡迎指正!

        完整代碼:

        html:

        <!DOCTYPE html>
        <html lang="en">
        <head>
         <meta charset="UTF-8">
         <title>Title</title>
         <script type="text/javascript" src="http://d3js.org/d3.v5.min.js">
         </script>
         <style>
         body{
         overflow: hidden;
         }
         #togo{
         width: 800px;
         height:500px;
         border:1px solid #ccc;
         user-select: none;
         }
         #togo text{
         font-size:10px;/*和js里保持一致*/
         fill:#1A2C3F;
         text-anchor: middle;
         }
         #togo .node-other{
        
         text-anchor: start;
         }
         #togo .health1{
         stroke:#92E1A2;
         }
         #togo .health2{
         stroke:orange;
         }
         #togo .health3{
         stroke:red;
         }
         #togo #cloud,#togo #database{
         fill:#ccc;
         }
         #togo .link{
         stroke:#E4E8ED;
         }
         #togo .node-title{
         font-size: 14px;
         }
         #togo .node-code circle{
         fill:#3F86F5;
         }
         #togo .node-code text{
         fill:#fff;
         }
         #togo .node-bg{
         fill:#fff;
         }
         #togo .arrow{
         fill:#E4E8ED;
         }
         </style>
         <script src="data.js"></script>
        </head>
        <body>
         <svg id="togo" width="800" height="500">
        
         </svg>
         <script src="togo.js"></script>
         <script>
        
         </script>
        
         <script>
         let t=new Togo('#togo',__options);
         t.render();
         </script>
        
        
        </body>
        </html>

        JS:

        const fontSize = 10;
        const symbolSize = 40;
        const padding = 10;
        
        /*
        * 調用 new Togo(svg,option).render();
        * */
        class Togo {
         /**/
         constructor(svg, option) {
         this.data = option.data;
         this.edges = option.edges;
         this.svg = d3.select(svg);
        
         }
        
         //主渲染方法
         render() {
         this.scale = 1;
         this.width = this.svg.attr('width');
         this.height = this.svg.attr('height');
         this.container = this.svg.append('g')
         .attr('transform', 'scale(' + this.scale + ')');
        
        
         this.initPosition();
         this.initDefineSymbol();
         this.initLink();
         this.initNode();
         this.initZoom();
        
         }
        
         //初始化節點位置
         initPosition() {
         let origin = [this.width / 2, this.height / 2];
         let points = this.getVertices(origin, Math.min(this.width, this.height) * 0.3, this.data.length);
         this.data.forEach((item, i) => {
         item.x = points[i].x;
         item.y = points[i].y;
         })
         }
        
         //根據多邊形獲取定位點
         getVertices(origin, r, n) {
         if (typeof n !== 'number') return;
         var ox = origin[0];
         var oy = origin[1];
         var angle = 360 / n;
         var i = 0;
         var points = [];
         var tempAngle = 0;
         while (i < n) {
         tempAngle = (i * angle * Math.PI) / 180;
         points.push({
         x: ox + r * Math.sin(tempAngle),
         y: oy + r * Math.cos(tempAngle),
         });
         i++;
         }
         return points;
         }
        
         //兩點的中心點
         getCenter(x1, y1, x2, y2) {
         return [(x1 + x2) / 2, (y1 + y2) / 2]
         }
        
         //兩點的距離
         getDistance(x1, y1, x2, y2) {
         return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
         }
        
         //兩點角度
         getAngle(x1, y1, x2, y2) {
         var x = Math.abs(x1 - x2);
         var y = Math.abs(y1 - y2);
         var z = Math.sqrt(x * x + y * y);
         return Math.round((Math.asin(y / z) / Math.PI * 180));
         }
        
        
         //初始化縮放器
         initZoom() {
         let self = this;
         let zoom = d3.zoom()
         .scaleExtent([0.7, 3])
         .on('zoom', function () {
         self.onZoom(this)
         });
         this.svg.call(zoom)
         }
        
         //初始化圖標
         initDefineSymbol() {
         let defs=this.container.append('svg:defs');
        
         //箭頭
         const marker = defs
         .selectAll('marker')
         .data(this.edges)
         .enter()
         .append('svg:marker')
         .attr('id', (link, i) => 'marker-' + i)
         .attr('markerUnits', 'userSpaceOnUse')
         .attr('viewBox', '0 -5 10 10')
         .attr('refX', symbolSize / 2 + padding)
         .attr('refY', 0)
         .attr('markerWidth', 14)
         .attr('markerHeight', 14)
         .attr('orient', 'auto')
         .attr('stroke-width', 2)
         .append('svg:path')
         .attr('d', 'M2,0 L0,-3 L9,0 L0,3 M2,0 L0,-3')
         .attr('class','arrow')
        
        
         //數據庫
         let database =defs.append('g')
         .attr('id','database')
         .attr('transform','scale(0.042)');
        
         database.append('path')
         .attr('d','M512 800c-247.42 0-448-71.63-448-160v160c0 88.37 200.58 160 448 160s448-71.63 448-160V640c0 88.37-200.58 160-448 160z')
        
         database.append('path')
         .attr('d','M512 608c-247.42 0-448-71.63-448-160v160c0 88.37 200.58 160 448 160s448-71.63 448-160V448c0 88.37-200.58 160-448 160z') ;
        
         database.append('path')
         .attr('d','M512 416c-247.42 0-448-71.63-448-160v160c0 88.37 200.58 160 448 160s448-71.63 448-160V256c0 88.37-200.58 160-448 160z') ;
        
         database.append('path')
         .attr('d','M64 224a448 160 0 1 0 896 0 448 160 0 1 0-896 0Z');
        
         //云
         let cloud=defs.append('g')
         .attr('id','cloud')
         .attr('transform','scale(0.042)')
         .append('path')
         .attr('d','M709.3 285.8C668.3 202.7 583 145.4 484 145.4c-132.6 0-241 102.8-250.4 233-97.5 27.8-168.5 113-168.5 213.8 0 118.9 98.8 216.6 223.4 223.4h418.9c138.7 0 251.3-118.8 251.3-265.3 0-141.2-110.3-256.2-249.4-264.5z')
        
        
        
         }
        
         //初始化鏈接線
         initLink() {
         this.drawLinkLine();
         this.drawLinkText();
         }
        
         //初始化節點
         initNode() {
         var self = this;
         //節點容器
         this.nodes = this.container.selectAll(".node")
         .data(this.data)
         .enter()
         .append("g")
         .attr("transform", function (d) {
         return "translate(" + d.x + "," + d.y + ")";
         })
         .call(d3.drag()
         .on("drag", function (d) {
         self.onDrag(this, d)
         })
         )
         .on('click', function () {
         alert()
         })
        
         //節點背景默認覆蓋層
         this.nodes.append('circle')
         .attr('r', symbolSize / 2 + padding)
         .attr('class', 'node-bg');
        
         //節點圖標
         this.drawNodeSymbol();
         //節點標題
         this.drawNodeTitle();
         //節點其他說明
         this.drawNodeOther();
         this.drawNodeCode();
        
         }
        
         //畫節點語言標識
         drawNodeCode() {
         this.nodeCodes = this.nodes.filter(item => item.type == 'app')
         .append('g')
         .attr('class','node-code')
         .attr('transform', 'translate(' + -symbolSize / 2 + ',' + symbolSize / 3 + ')')
        
         this.nodeCodes
         .append('circle')
         .attr('r', d => fontSize / 2 * d.code.length / 2 + 3)
        
         this.nodeCodes
         .append('text')
         .attr('dy', fontSize / 2)
         .text(item => item.code);
        
         }
        
         //畫節點圖標
         drawNodeSymbol() {
         //繪制節點
         this.nodes.filter(item=>item.type=='app')
         .append("circle")
         .attr("r", symbolSize / 2)
         .attr("fill", '#fff')
         .attr('class', function (d) {
         return 'health'+d.health;
         })
         .attr('stroke-width', '5px')
        
        
         this.nodes.filter(item=>item.type=='database')
         .append('use')
         .attr('xlink:href','#database')
         .attr('x',function () {
         return -this.getBBox().width/2
         })
         .attr('y',function () {
         return -this.getBBox().height/2
         })
        
         this.nodes.filter(item=>item.type=='cloud')
         .append('use')
         .attr('xlink:href','#cloud')
         .attr('x',function () {
         return -this.getBBox().width/2
         })
         .attr('y',function () {
         return -this.getBBox().height/2
         })
         }
        
         //畫節點右側信息
         drawNodeOther() {
         //如果是應用的時候
         this.nodeOthers = this.nodes.filter(item => item.type == 'app')
         .append("text")
         .attr("x", symbolSize / 2 + padding)
         .attr("y", -5)
         .attr('class','node-other')
        
         this.nodeOthers.append('tspan')
         .text(d => d.time + 'ms');
        
         this.nodeOthers.append('tspan')
         .text(d => d.rpm + 'rpm')
         .attr('x', symbolSize / 2 + padding)
         .attr('dy', '1em');
        
         this.nodeOthers.append('tspan')
         .text(d => d.epm + 'epm')
         .attr('x', symbolSize / 2 + padding)
         .attr('dy', '1em')
         }
        
         //畫節點標題
         drawNodeTitle() {
         //節點標題
         this.nodes.append("text")
         .attr('class','node-title')
         .text(function (d) {
         return d.name;
         })
         .attr("dy", symbolSize)
        
         this.nodes.filter(item => item.type == 'app').append("text")
         .text(function (d) {
         return d.active + '/' + d.total;
         })
         .attr('dy', fontSize / 2)
         .attr('class','node-call')
        
         }
        
         //畫節點鏈接線
         drawLinkLine() {
         let data = this.data;
         if (this.lineGroup) {
         this.lineGroup.selectAll('.link')
         .attr(
         'd', link => genLinkPath(link),
         )
         } else {
         this.lineGroup = this.container.append('g')
        
        
         this.lineGroup.selectAll('.link')
         .data(this.edges)
         .enter()
         .append('path')
         .attr('class', 'link')
         .attr(
         'marker-end', (link, i) => 'url(#' + 'marker-' + i + ')'
         ).attr(
         'd', link => genLinkPath(link),
         ).attr(
         'id', (link, i) => 'link-' + i
         )
         .on('click', () => { alert() })
         }
        
         function genLinkPath(d) {
         let sx = data[d.source].x;
         let tx = data[d.target].x;
         let sy = data[d.source].y;
         let ty = data[d.target].y;
         return 'M' + sx + ',' + sy + ' L' + tx + ',' + ty;
         }
         }
        
        
         drawLinkText() {
         let data = this.data;
         let self = this;
         if (this.lineTextGroup) {
         this.lineTexts
         .attr('transform', getTransform)
        
         } else {
         this.lineTextGroup = this.container.append('g')
        
         this.lineTexts = this.lineTextGroup
         .selectAll('.linetext')
         .data(this.edges)
         .enter()
         .append('text')
         .attr('dy', -2)
         .attr('transform', getTransform)
         .on('click', () => { alert() })
        
         this.lineTexts
         .append('tspan')
         .text((d, i) => this.data[d.source].lineTime + 'ms,' + this.data[d.source].lineRpm + 'rpm');
        
         this.lineTexts
         .append('tspan')
         .text((d, i) => this.data[d.source].lineProtocol)
         .attr('dy', '1em')
         .attr('dx', function () {
         return -this.getBBox().width / 2
         })
         }
        
         function getTransform(link) {
         let s = data[link.source];
         let t = data[link.target];
         let p = self.getCenter(s.x, s.y, t.x, t.y);
         let angle = self.getAngle(s.x, s.y, t.x, t.y);
         if (s.x > t.x && s.y < t.y || s.x < t.x && s.y > t.y) {
         angle = -angle
         }
         return 'translate(' + p[0] + ',' + p[1] + ') rotate(' + angle + ')'
         }
         }
        
        
         update(d) {
         this.drawLinkLine();
         this.drawLinkText();
         }
        
         //拖拽方法
         onDrag(ele, d) {
         d.x = d3.event.x;
         d.y = d3.event.y;
         d3.select(ele)
         .attr('transform', "translate(" + d3.event.x + "," + d3.event.y + ")")
         this.update(d);
         }
        
         //縮放方法
         onZoom(ele) {
         var transform = d3.zoomTransform(ele);
         this.scale = transform.k;
         this.container.attr('transform', "translate(" + transform.x + "," + transform.y + ")scale(" + transform.k + ")")
         }
        
        }

        數據:

        let __options={
         data:[{
         type:'app',
         name: 'monitor-web-server',
         time: 30,
         rpm: 40,
         epm: 50,
         active: 3,
         total: 5,
         code: 'java',
         health: 1,
         lineProtocol: 'http',
         lineTime: 12,
         lineRpm: 34,
         }, {
         type:'database',
         name: 'Mysql',
         time: 30,
         rpm: 40,
         epm: 50,
         active: 3,
         total: 5,
         code: 'java',
         health: 2,
         lineProtocol: 'http',
         lineTime: 12,
         lineRpm: 34,
        
         },
         {
         type:'app',
         name: 'Redis',
         time: 30,
         rpm: 40,
         epm: 50,
         active: 3,
         total: 5,
         code: 'java',
         health: 3,
         lineProtocol: 'http',
         lineTime: 12,
         lineRpm: 34,
        
         }, {
         type:'cloud',
         name: 'ES',
         time: 30,
         rpm: 40,
         epm: 50,
         active: 3,
         total: 5,
         code: 'java',
         health: 1,
         lineProtocol: 'http',
         lineTime: 12,
         lineRpm: 34,
         value: 100
         }
         ],
         edges: [
         {
         source: 0,
         target: 3,
         }, {
         source: 1,
         target: 2,
         }
         , {
         source: 1,
         target: 3,
         },
         {
         source: 0,
         target: 1,
         },
         {
         source: 0,
         target: 2,
         }
         // {
         // source: 3,
         // target: 2,
         // },
         ]
        }

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        如何用D3.js實現拓撲圖

        如何用D3.js實現拓撲圖:這篇文章主要介紹了關于如何用D3.js實現拓撲圖,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下最近寫項目需要畫出應用程序調用鏈的網路拓撲圖,完全自己寫需要花費些時間,那么首先想到的是echarts,但echarts的自定義寫法寫起來非常麻煩,而
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 18观看免费永久视频| 美女巨胸喷奶水视频www免费| 99热在线免费播放| 亚洲区小说区图片区QVOD| 中国毛片免费观看| 亚洲人成伊人成综合网久久久| 国偷自产一区二区免费视频| 亚洲av不卡一区二区三区| 91精品国产免费入口| 亚洲人和日本人jizz| 成人免费视频88| 日韩大片免费观看视频播放| 不卡精品国产_亚洲人成在线| 岛国精品一区免费视频在线观看| 亚洲开心婷婷中文字幕| 一区二区免费视频| 国产色在线|亚洲| 免费一级毛片清高播放| 9久久免费国产精品特黄| 亚洲高清在线观看| 久久久高清免费视频| 久久亚洲AV成人无码国产电影 | 国产免费一级高清淫曰本片| 精品国产人成亚洲区| 十八禁无码免费网站| 亚洲乱码av中文一区二区| 亚洲精品国产va在线观看蜜芽| a毛片免费全部播放完整成| 亚洲欧洲日产专区| 国产又大又粗又硬又长免费| 成人av片无码免费天天看| 亚洲理论片在线中文字幕| 国产在线观看免费完整版中文版| 国产精品免费观看视频| 亚洲午夜精品一区二区公牛电影院| 女人18毛片特级一级免费视频| 精品国产免费人成网站| 国产成人精品日本亚洲18图| 亚洲国产成人久久精品99| 亚洲视频免费一区| 亚洲免费视频一区二区三区|