效果圖
安裝D3.js
npm install d3 --save-dev
編寫topo.js
import * as d3 from 'd3'
import { uniqueId } from '@/lib/util'
const fontSize = 10;
const symbolSize = 40;
const padding = 10;
const colors = {
primary: '#409EFF',
warning: '#E6A23C',
danger: '#F56C6C'
};
const lineColor = '#ccc';
const boxBg = '#f5f5f5';
const boxBorder = '#ccc';
/*
* 調(diào)用 new Topo(svg,option).render();
* */
export class Topo {
currentNode = null
/**/
constructor(svg, option) {
this.data = option.data;
this.edges = option.edges;
this.boxs = option.boxs;
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.initBox();
this.initLink();
this.initNode();
this.initZoom();
}
// 初始化節(jié)點位置
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) => {
if (!item.x || !item.y) {
item.x = points[i].x;
item.y = points[i].y;
}
})
}
// 根據(jù)多邊形獲取定位點
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');
// 箭頭
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');
// 數(shù)據(jù)庫
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');
const nginx = defs.append('g')
.attr('id', 'nginx')
.attr('transform', 'scale(0.042)')
nginx.append('path')
.attr('d', 'M512 0L68.48 256v512L512 1024l443.52-256V256z m256 707.84c0 30.08-27.552 55.04-65.248 55.04-26.912 0-57.632-10.88-76.832-34.56l-256-304.672v284.16c0 30.752-24.32 55.04-54.368 55.04H312.32c-30.752 0-55.04-25.6-55.04-55.04V316.16c0-30.08 26.88-55.04 64-55.04 27.552 0 58.88 10.88 78.08 34.56l254.72 304.672V316.16c0-30.752 25.6-55.04 55.04-55.04h3.2c30.72 0 55.04 25.6 55.04 55.04v391.68z')
const gslb = defs.append('g')
.attr('id', 'gslb')
.attr('transform', 'scale(0.042)')
gslb.append('path')
.attr('d', 'M776.043 548.63c-24.768 0.106-48.128 6.378-69.142 16.469l-89.45-133.867c33.365-29.739 54.656-72.683 54.4-120.704-0.427-89.237-73.195-161.621-162.496-161.195-89.28 0.427-161.43 73.494-161.024 162.624 0.213 48.064 21.973 90.688 55.381 120.256l-88.043 134.678c-21.205-9.963-44.437-15.936-69.333-15.83-89.152 0.363-161.43 73.366-161.003 162.624 0.299 89.152 73.195 161.451 162.496 160.96 81.451-0.32 148.054-61.269 158.87-139.84l210.73-1.002c11.435 78.506 78.592 138.858 160.107 138.517 89.237-0.427 161.43-73.301 161.13-162.56-0.469-89.237-73.471-161.536-162.623-161.13z m-158.87 139.84l-210.73 0.96a161.13 161.13 0 0 0-52.971-97.6L441.6 457.11c21.141 9.962 44.437 16.042 69.27 15.829a159.957 159.957 0 0 0 69.162-16.384L669.525 590.4a160.32 160.32 0 0 0-52.352 98.07z')
const ldap = defs.append('g')
.attr('id', 'ldap')
.attr('transform', 'scale(0.042)')
ldap.append('path')
.attr('d', 'M128.4096 615.512064h-1.47456c-13.272064 0-24.085504 10.816512-24.085504 24.088576v214.135808c0 13.272064 10.81344 24.082432 24.085504 24.082432h131.23584c13.272064 0 24.08448-10.810368 24.08448-24.082432 0-13.267968-10.812416-24.085504-24.08448-24.085504H152.493056V639.601664c0-13.272064-10.73152-24.0896-24.083456-24.0896z m377.895936 131.155968c0-41.86112-10.40384-73.811968-30.72-95.847424-21.464064-23.507968-52.511744-35.308544-93.965312-35.308544h-69.14048c-13.266944 0-24.08448 10.816512-24.08448 24.088576v214.135808c0 13.272064 10.816512 24.083456 24.08448 24.083456h69.14048c41.45152 0 72.585216-11.795456 93.965312-35.303424 20.400128-22.368256 30.72-54.313984 30.72-95.848448z m-66.435072 63.081472c-14.256128 14.00832-40.633344 20.232192-62.830592 20.232192h-38.749184v-167.936h38.749184c28.259328 0 49.803264 6.549504 62.830592 19.905536 12.696576 13.026304 19.089408 29.080576 19.089408 58.487808-0.001024 36.378624-7.706624 58.165248-19.089408 69.310464zM574.54592 631.2448l-79.628288 214.135808c-5.896192 15.725568 5.818368 32.52224 22.611968 32.52224h1.964032c10.24 0 19.336192-6.470656 22.69184-16.054272l17.531904-49.728512h89.62048l17.531904 49.728512c3.439616 9.663488 12.531712 16.054272 22.69184 16.054272h1.143808c16.795648 0 28.428288-16.794624 22.611968-32.52224L633.690112 631.2448c-3.520512-9.42592-12.531712-15.732736-22.607872-15.732736h-14.009344c-9.995264 0-19.006464 6.227968-22.526976 15.732736z m0.079872 138.851328l28.919808-82.410496h1.063936l28.672 82.410496h-58.655744z m254.528512-154.584064h-81.677312c-13.272064 0-24.08448 10.816512-24.08448 24.088576v214.135808c0 13.272064 10.812416 24.082432 24.08448 24.082432h1.805312c13.267968 0 24.08448-10.810368 24.08448-24.082432v-76.598272H828.416c62.180352 0 93.30688-27.195392 93.30688-81.1776-0.001024-53.661696-31.128576-80.448512-92.568576-80.448512z m37.51936 108.0576c-8.603648 6.631424-22.120448 10.319872-40.716288 10.319872H773.36576v-74.220544h52.59264c18.188288 0 31.783936 3.2768 40.38656 10.322944 8.599552 6.637568 13.188096 14.665728 13.188096 26.049536 0.001024 13.678592-4.258816 20.564992-12.859392 27.528192z')
ldap.append('path')
.attr('d', 'M312.776704 524.178432h-92.16V192.216064c0-47.993856 39.046144-87.04 87.04-87.04h414.797824c47.993856 0 87.04 39.046144 87.04 87.04v331.961344h-92.16V197.336064H312.776704v326.842368z')
ldap.append('path')
.attr('d', 'M622.244864 335.669248H400.73216c-16.965632 0-30.72-13.754368-30.72-30.72s13.754368-30.72 30.72-30.72h221.512704c16.965632 0 30.72 13.754368 30.72 30.72s-13.754368 30.72-30.72 30.72z')
ldap.append('path')
.attr('d', 'M622.244864 435.24608H400.73216c-16.965632 0-30.72-13.754368-30.72-30.72s13.754368-30.72 30.72-30.72h221.512704c16.965632 0 30.72 13.754368 30.72 30.72s-13.754368 30.72-30.72 30.72z')
const OpenResty = defs.append('g')
.attr('id', 'OpenResty')
.attr('transform', 'scale(0.042)')
OpenResty.append('path')
.attr('d', 'M407.3 960.3l-321-110v-642l321 82z')
OpenResty.append('path')
.attr('d', 'M407.3 960.3l450-240v-600l-450 170z')
OpenResty.append('path')
.attr('d', 'M86.3 208.3l321 82 450-170-344.4-56.6z')
OpenResty.append('path')
.attr('d', 'M360.1 348.9v80l-239-60v-80l239 60z m-239 48.3l239 60v-10l-239-60v10z m0 23l239 60v-10l-239-60v10z m0 23l239 60v-10l-239-60v10z')
OpenResty.append('path')
.attr('d', 'M135.5 308.4v34l210.2 53v-34zM135.5 363.4l210.2 53v-13.3l-210.2-53z')
OpenResty.append('path')
.attr('d', 'M407.3 894.1v-5.2l-174.4-55.3-1.3 4.8zM231.6 809.3L407.3 864v-5.3l-174.4-54.3zM231.6 780.1l175.7 53.7v-5.2l-174.4-53.4zM407.3 707.9l-174.4-49.3-1.3 4.8 175.7 49.7zM231.6 692.6l175.7 50.7v-5.2l-174.4-50.4zM231.6 750.9l175.7 52.7v-5.2l-174.4-52.3zM231.6 721.8l175.7 51.7v-5.3l-174.4-51.3z')
OpenResty.append('path')
.attr('d', 'M339.3 540.8c-9.4-3.4-17 1.6-17 11.2s7.6 20.1 17 23.2 17-1.9 17-11.2-7.6-19.8-17-23.2zM339.3 603.6c-3.9-1.2-7 1-7 4.9s3.1 8.1 7 9.3 7-1 7-4.9c0-3.9-3.2-8-7-9.3z')
OpenResty.append('path')
.attr('d', 'M737.7 753.9m-200 0a200 200 0 1 0 400 0 200 200 0 1 0-400 0Z')
OpenResty.append('path')
.attr('d', 'M799.5 563.7c53.5 36.8 87.3 90.6 87.3 150.6 0 110.9-115.4 200.8-257.8 200.8-3.4 0-6.7-0.1-10-0.2 33.2 24.6 74.3 39.1 118.8 39.1 110.5 0 200-89.5 200-200-0.1-89-58.1-164.3-138.3-190.3z')
OpenResty.append('path')
.attr('d', 'M804.3 760s-7.5-4.5-12.5-6-2.5-9-2.5-9 3 4.5 11.5 6 22.5 3.5 26.5 8.5 4.5 8 6.5 10 3.5 7 3.5 7-8.3-1.3-10-5c-1.7-3.7-3.5-9.5-5-8s-0.5 7-6 7-7-5-11-6-1-4.5-1-4.5z m-22.5-104l14-2.5 7-7.5-2-7 3-11-4-6s0-11.5-4.5-13.5-3-14.5-3-14.5l0.5-2.5-5 4.5 3 13 4.5 13 0.5 22.5-10.5 6.5-8 10.5 4.5-5.5z m10.5-25.5l-3-4-3.5 0.5-1 6.5 3.5 0.5 4-3.5zM831.8 803s-0.5-9-4.5-9-5.5-10-5.5-10l-8-8.5s0 12.5 0.5 14.5-5.5 5-7 4-7-9.5-7-9.5 2.2-4.8-1-4.5c-0.3 0-0.5 0.1-0.7 0.1-0.8-0.1-2.1-0.3-4.3-0.6l-10.4-1.3-1.1 4.3s-6 5-9.5 6.5-7.5 16-12 16-11 0.5-11 0.5-8 13.5-5.5 18.5 3.5 10 3 16 0.5 5 9 3.5 15.5-13 25-11 12.5 11.5 12.5 11.5l8-7s-1 5-2.5 5.5 1.5 1 3.5 4.5 12.9 8.4 27-5 9-25 9-25l-7.5-14z m-219.5-12c1-9.5-4.5-7-4-20.5s19-45 17.5-45-10 6.5-13 6-16-30-16-34.5-3.5-21.5-3.5-21.5 4 11.5 7 12 4 13 6.5 19 10.5 16 15.5 15.5 20.5-28.5 20.5-28.5l-8.5-5-9 5.5s-2.5-6-5.5-9.5-2.5-12-0.5-12 4.3 5.8 14.5 12.5 19.5 0 21.5 1.5 10 8 10.5 12 10.5 31.5 12 33.5 7.5-7 10-18.5 14.5-17 18.5-20 3.5 3.5 6 9.5 9 9.5 12 12 0.5 10.5 5.5 10.5 9-8.5 9-8.5l-3.5-9.5c-3.5-9.5 1.5-10.5 6-12.5s12.5-9.5 18-18-4.5-16.5-7.5-24 3.5-7 7-7.5 7 19.5 7 19.5l6.5-3.5s-1.5-6.5-4.5-12.5 4-6 12.5-15 3.6-13.3 4-24.5-10.5-10-10.5-10-2.5 4 0.5-10 23.5-6 28.5-6.5c3.9-0.4 8.8-10.1 10.7-14.2-23.4-9.6-48.9-14.9-75.8-14.9-106.8 0-194.1 83.7-199.7 189.2 2.4 1.3 5.6 2.7 9.3 3.4 8 1.5 4.5 14 5 20.5s2 13.5 5 20-1 10.5-2.5 15 2 11.5 5 11.5-5.5 15.5 4 31.5 23.5-1.5 30-24.5 17.5-20 18.5-29.5z m129-43.5l4 8 8.5 4s3-12 8-18-3-11.5-6.5-12.5l-14 18.5z m83.2-137c0.3 1 0.8 1.5 0.8 1.5s-0.3-0.6-0.8-1.5z m-60.1 161.8c-2.6-0.8-6.8-2-13.2-3.8-16-4.5-12-3-17.5-6.5s-0.5-5 0.5-9.5-5-19-5-19l-6-5-1.5 9-6.5 2 8 19s13.5 11.5 22 15.5c5.1 2.4 13.4 0.3 19.2-1.7zM619.8 826s8-14.5 9.5-21.5-1-18-1-18-10.5 8-8.5 9-3 5.5-4 13.5 4 17 4 17z m201.3-253.9c-4.4 5.4-10.3 13.1-10.3 15.9 0 4.5 7 4.5 7.5 8 0.4 2.7 4.5 11 6.2 14.5-0.4-1.3-0.6-3.4 0.8-6 2.5-4.5 3-15 0.5-19.5-1.2-2.1 0.3-6 2.2-9.6l-6.9-3.3zM769 770.5c1.4-0.6 2.2-1 2.2-1s-1 0.4-2.2 1z m-1.7 2.5c-1.5-0.6 0.2-1.7 1.8-2.5-1.2 0.5-2.8 1.1-4.6 1.8 4 1.2 4.3 1.3 2.8 0.7z')
// 云
const cloud = defs.append('g')
.attr('id', 'cloud')
.attr('transform', 'scale(0.042)')
cloud.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')
const dns = defs.append('g')
.attr('id', 'dns')
.attr('transform', 'scale(0.042)')
dns.append('path')
.attr('d', 'M449.774933 765.013333h47.650134v148.855467c56.6784-12.305067 107.6992-67.8656 141.312-148.846933h51.2c-17.442133 47.086933-40.32 88.064-67.362134 120.3968a374.801067 374.801067 0 0 0 150.818134-120.405334h57.617066C756.693333 884.650667 624.418133 964.266667 473.6 964.266667c-150.8096 0-283.093333-79.616-357.410133-199.253334h57.617066a374.801067 374.801067 0 0 0 150.818134 120.405334c-27.042133-32.341333-49.92-73.301333-67.370667-120.405334h51.2c33.621333 80.981333 84.642133 136.5504 141.320533 148.855467V765.021867z m0-422.4V169.873067c-62.097067 13.482667-117.410133 78.890667-150.468266 172.757333h-50.261334c18.176-57.173333 44.0576-106.606933 75.579734-144.298667-69.12 30.225067-127.342933 80.853333-167.125334 144.298667H102.4C173.320533 209.800533 312.951467 119.466667 473.6 119.466667S773.879467 209.800533 844.8 342.613333h-55.099733c-39.7824-63.4368-98.005333-114.065067-167.125334-144.298666 31.522133 37.700267 57.3952 87.125333 75.588267 144.298666h-50.261333c-33.066667-93.866667-88.379733-159.266133-150.4768-172.7488V342.613333h-47.650134zM68.266667 398.336h107.861333c47.931733 0 83.882667 13.243733 108.680533 39.739733 23.552 24.840533 35.541333 60.859733 35.541334 108.0576 0 46.779733-11.989333 82.807467-35.541334 108.0576-24.797867 26.496-60.7488 39.748267-108.680533 39.748267H68.266667V398.327467z m48.349866 41.3952v212.804267h50.414934c36.778667 0 63.6416-8.695467 80.580266-25.668267 16.5376-17.390933 24.797867-44.296533 24.797867-80.733867 0-37.265067-8.260267-64.5888-24.797867-81.152-16.938667-16.9728-43.8016-25.250133-80.580266-25.250133h-50.414934z m249.1904-41.403733h48.349867l145.877333 213.2224h1.646934V398.327467h48.768v295.611733h-47.112534L415.803733 477.824h-1.646933V693.930667h-48.349867V398.327467zM772.437333 392.533333c34.7136 0 61.986133 7.04 81.408 21.5296 20.667733 15.317333 32.648533 39.338667 35.541334 71.620267h-47.931734c-4.138667-18.210133-11.989333-31.4624-22.7328-39.330133-10.743467-8.277333-27.272533-12.0064-48.759466-12.0064-18.602667 0-32.648533 2.4832-42.564267 7.867733-12.398933 6.212267-18.184533 16.554667-18.184533 30.634667 0 12.424533 6.613333 22.775467 20.6592 30.225066 6.203733 3.310933 23.1424 9.5232 50.414933 18.218667 40.0896 12.416 65.706667 22.357333 77.277867 28.9792C883.2 565.589333 896 586.709333 896 614.033067c0 26.496-10.325333 47.616-30.993067 62.933333C844.347733 691.8656 815.0016 699.733333 777.386667 699.733333c-36.360533 0-64.878933-7.04-85.128534-21.111466-24.789333-17.390933-38.4256-44.714667-40.4992-82.389334h47.940267c3.3024 22.357333 11.1616 38.5024 23.970133 48.0256 11.5712 8.277333 29.3376 12.834133 53.717334 12.834134 21.495467 0 38.852267-3.729067 51.242666-10.769067 12.398933-7.4496 19.012267-16.9728 19.012267-29.397333 0-15.726933-9.506133-28.151467-27.690667-37.256534-5.7856-2.901333-24.789333-9.5232-57.437866-19.456-36.369067-11.5968-59.093333-19.882667-67.771734-24.840533-22.7328-13.6704-33.885867-33.536-33.885866-59.6224s10.743467-46.779733 33.058133-61.696C714.581333 399.581867 740.616533 392.533333 772.437333 392.533333z')
const docker = defs.append('g')
.attr('id', 'docker')
.attr('transform', 'scale(0.042)')
docker.append('path')
.attr('d', 'M699.88718 472.6h-132.2v-118.8h132.2v118.8z m0-408.6h-132.2v121.4h132.2V64z m156.4 289.6H724.08718v118.8h132.2v-118.8z m-312.6-144.2h-132.2v120.2h132.2v-120.2z m156.2 0h-132.2v120.2h132.2v-120.2z m553.6 200c-28.8-19.4-95.2-26.4-146.2-16.8-6.6-48-33.4-89.8-82.2-127.4l-28-18.6-18.6 28c-36.8 55.6-46.8 147.2-7.4 207.6-17.4 9.4-51.6 22.2-96.8 21.4H4.88718c-17.4 101.6 11.6 233.6 88 324.2 74.2 87.8 185.4 132.4 330.8 132.4 314.8 0 547.8-145 656.8-408.4 42.8 0.8 135.2 0.2 182.6-90.4 3-5 13.2-26.4 17-34.2l-26.6-17.8z m-1022.2-55.8h-132v118.8h132.2v-118.8z m156.2 0h-132.2v118.8h132.2v-118.8z m156.2 0h-132.2v118.8h132.2v-118.8z m-156.2-144.2h-132.2v120.2h132.2v-120.2z')
const gateway = defs.append('g')
.attr('id', 'gateway')
.attr('transform', 'scale(0.042)')
gateway.append('path')
.attr('d', 'M264.815304 86.77287v850.498782h573.217392V86.77287H264.815304z m286.630957 761.010087a48.217043 48.217043 0 1 1-0.044522-96.389566 48.217043 48.217043 0 0 1 0.044522 96.389566z m0-187.392a27.826087 27.826087 0 1 1 0 55.652173 27.826087 27.826087 0 0 1 0-55.652173z m-27.826087-64.912696a27.826087 27.826087 0 1 1 55.652174 0 27.826087 27.826087 0 0 1-55.652174 0z m185.032348-138.195478H394.195478V411.336348h314.457044v45.946435z m0-82.098087H394.195478V329.282783h314.457044v45.901913z m0-79.293218H394.195478V167.891478h314.457044v128z')
gateway.append('path')
.attr('d', 'M551.446261 799.521391m-18.565565 0a18.565565 18.565565 0 1 0 37.13113 0 18.565565 18.565565 0 1 0-37.13113 0Z')
gateway.append('path')
.attr('d', 'M437.337043 212.368696h228.173914v42.651826H437.337043z')
const _switch = defs.append('g')
.attr('id', 'switch')
.attr('transform', 'scale(0.042)')
_switch.append('path')
.attr('d', 'M264.32 731.84h79.04a20.16 20.16 0 0 0 20.16-20.16v-18.88a20.16 20.16 0 0 0-20.16-20.16H264.32a20.16 20.16 0 0 0-20.16 20.16v18.88a20.16 20.16 0 0 0 20.16 20.16z m0 118.72h79.04a20.16 20.16 0 0 0 20.16-20.16v-18.88a20.16 20.16 0 0 0-20.16-20.16H264.32a20.16 20.16 0 0 0-20.16 20.16V832a20.16 20.16 0 0 0 20.16 20.16z m187.52-118.72a29.44 29.44 0 0 0 29.44-29.44 29.44 29.44 0 0 0-29.44-29.44 29.44 29.44 0 0 0-29.44 29.44 29.44 29.44 0 0 0 29.44 29.44z m0 118.72a29.44 29.44 0 0 0 29.44-29.44 29.44 29.44 0 0 0-29.44-29.44 29.44 29.44 0 0 0-29.44 29.44 29.44 29.44 0 0 0 29.44 29.44z m119.36-118.72a29.44 29.44 0 0 0 29.44-29.44 29.44 29.44 0 0 0-29.44-29.44 29.44 29.44 0 0 0-29.44 29.44 29.44 29.44 0 0 0 29.44 29.44z m0 118.72a29.44 29.44 0 0 0 29.44-29.44 29.44 29.44 0 0 0-29.44-29.44 29.44 29.44 0 0 0-29.44 29.44 29.44 29.44 0 0 0 29.44 29.44z m118.4-118.72a29.44 29.44 0 0 0 29.44-29.44 29.44 29.44 0 0 0-29.44-29.44 29.44 29.44 0 0 0-29.44 29.44 29.44 29.44 0 0 0 29.44 29.44z m0 118.72a29.44 29.44 0 0 0 29.44-29.44 29.44 29.44 0 0 0-29.44-29.44 29.44 29.44 0 0 0-29.44 29.44 29.44 29.44 0 0 0 29.44 29.44z m119.36-118.72a29.44 29.44 0 0 0 29.44-29.44 29.44 29.44 0 0 0-29.44-29.44 29.44 29.44 0 0 0-29.44 29.44 29.44 29.44 0 0 0 29.44 29.44z m0 118.72a29.44 29.44 0 0 0 29.44-29.44 29.44 29.44 0 0 0-29.44-29.44 29.44 29.44 0 0 0-29.44 29.44 29.44 29.44 0 0 0 29.44 29.44z m0 0')
_switch.append('path')
.attr('d', 'M960 610.88L898.24 157.44a29.76 29.76 0 0 0-29.44-25.6H217.92a29.76 29.76 0 0 0-29.44 25.6l-64 453.44v322.56A34.24 34.24 0 0 0 160 967.68h768a34.24 34.24 0 0 0 32-34.24V611.52zM512 192l-3.84 64h289.6v64h-294.4l-4.16 64-187.2-96z m-205.12 229.44h293.44l2.56-69.44L800 449.6l-204.8 104.32 2.56-64H299.52z m593.6 486.4H184.32v-296.96h715.84z m0 0')
const tidb = defs.append('g')
.attr('id', 'tidb')
.attr('transform', 'scale(0.042)')
tidb.append('path')
.attr('d', 'M667.692 690.099h123.031v27.324H667.692z')
tidb.append('path')
.attr('d', 'M715.546 704.638h27.324v128.949h-27.324zM787.253 777.259h27.324v56.584h-27.324zM787.253 737.953h27.324v23.415h-27.324zM562.681 669.124a894.203 894.203 0 0 1-53.814 1.608c-147.778 0-274.579-35.833-329.148-86.976v86.976c0 63.231 147.363 114.486 329.148 114.486 21.935 0 28.7-1.796 49.434-3.219l-0.02 28.502c-20.791 1.504-27.538 3.338-49.414 3.338-185.513 0-337.998-56.471-355.962-128.797h-1.808V241.428c0-79.029 160.187-143.108 357.77-143.108s357.751 64.078 357.751 143.108v354.986l-28.622 0.487V440.649c-54.55 51.142-181.352 86.995-329.129 86.995s-274.579-35.852-329.148-86.995v86.995c0 63.231 147.363 114.486 329.148 114.486a942.32 942.32 0 0 0 54.927-1.587l-1.113 28.581z m-53.814-542.183c-181.785 0-329.148 51.255-329.148 114.486s147.363 114.486 329.148 114.486 329.129-51.255 329.129-114.486-147.345-114.486-329.129-114.486z m329.129 170.6c-54.55 51.142-181.352 86.995-329.129 86.995s-274.579-35.852-329.148-86.995v86.995c0 63.231 147.363 114.486 329.148 114.486s329.129-51.255 329.129-114.486v-86.995zM208.34 253.516v-16.721c51.425 44.91 166.645 76.186 300.527 76.186s249.102-31.277 300.527-76.186v16.721c-58.599 44.006-171.221 73.776-300.527 73.776s-241.928-29.77-300.527-73.776z')
tidb.append('path')
.attr('d', 'M745.683 928.162l-149.077-86.538 0.402-172.383 149.479-85.844 149.04 86.538-0.402 172.383-149.442 85.844zM623.93 825.916l121.826 70.685 122.118-70.137 0.329-140.821-121.789-70.685-122.155 70.137-0.329 140.821z')
const user = defs.append('g')
.attr('id', 'user')
.attr('transform', 'scale(0.042)')
user.append('path')
.attr('d', 'M868.790857 726.747429a344.649143 344.649143 0 0 0-98.742857-69.046858 228.059429 228.059429 0 0 0 84.845714-177.737142 229.961143 229.961143 0 0 0-232.301714-228.571429 228.717714 228.717714 0 0 0-140.288 406.308571c-36.278857 16.822857-69.632 39.862857-98.742857 69.046858a340.626286 340.626286 0 0 0-100.132572 233.033142 9.142857 9.142857 0 0 0 9.142858 9.362286h64A9.069714 9.069714 0 0 0 365.714286 960.365714a258.340571 258.340571 0 0 1 76.214857-175.469714 258.998857 258.998857 0 0 1 184.32-76.288c69.632 0 135.094857 27.062857 184.32 76.288a259.364571 259.364571 0 0 1 76.288 175.469714c0.146286 4.900571 4.242286 8.777143 9.142857 8.777143h64c5.12 0 9.289143-4.242286 9.142857-9.362286a339.894857 339.894857 0 0 0-100.352-233.033142zM626.249143 626.322286a145.042286 145.042286 0 0 1-103.424-42.861715 146.505143 146.505143 0 0 1 101.961143-249.709714 147.163429 147.163429 0 0 1 104.009143 41.764572c28.379429 27.794286 43.885714 64.950857 43.885714 104.448 0 39.131429-15.213714 75.776-42.861714 103.497142a145.554286 145.554286 0 0 1-103.497143 42.788572zM340.041143 510.098286a293.010286 293.010286 0 0 1 3.364571-83.382857 9.216 9.216 0 0 0-5.12-10.020572 145.773714 145.773714 0 0 1-86.381714-137.728 145.554286 145.554286 0 0 1 41.398857-97.792 145.554286 145.554286 0 0 1 106.569143-44.251428 146.139429 146.139429 0 0 1 121.563429 67.291428 9.142857 9.142857 0 0 0 10.605714 3.657143c20.114286-7.021714 41.398857-11.922286 63.195428-14.262857a9.142857 9.142857 0 0 0 7.241143-13.165714A228.937143 228.937143 0 0 0 401.554286 54.857143C274.870857 52.882286 169.252571 156.818286 169.252571 283.282286c0 71.826286 33.060571 135.826286 84.845715 177.737143-36.352 16.822857-69.851429 40.009143-98.889143 69.046857A339.894857 339.894857 0 0 0 54.857143 763.172571a9.142857 9.142857 0 0 0 9.142857 9.435429h64.146286a9.069714 9.069714 0 0 0 9.142857-8.777143 258.340571 258.340571 0 0 1 76.214857-175.542857 257.974857 257.974857 0 0 1 119.661714-68.169143 9.142857 9.142857 0 0 0 6.802286-9.947428z')
const innerUser = defs.append('g')
.attr('id', 'innerUser')
.attr('transform', 'scale(0.042)')
innerUser.append('path')
.attr('d', 'M587.310545 549.050182a266.053818 266.053818 0 0 0 111.057455-216.157091c0-148.200727-122.600727-268.846545-273.221818-268.846546S152.576 184.133818 152.576 332.334545c0 88.436364 44.032 167.098182 111.057455 216.064C109.102545 611.141818 0 761.297455 0 935.377455c0 23.272727 19.176727 42.077091 42.821818 42.07709a42.449455 42.449455 0 0 0 42.821818-42.07709c0-184.692364 152.482909-334.848 340.154182-334.848s340.247273 150.155636 340.247273 334.848c0 23.272727 19.083636 42.077091 42.821818 42.07709a42.449455 42.449455 0 0 0 42.635636-42.07709c-0.558545-174.08-109.754182-323.584-264.192-386.327273zM237.474909 332.334545c0-101.841455 84.247273-184.692364 187.671273-184.692363 103.330909 0 187.671273 82.850909 187.671273 184.692363 0 101.748364-84.247273 184.692364-187.671273 184.692364s-187.671273-82.850909-187.671273-184.692364z m642.792727 148.852364a238.778182 238.778182 0 0 0 98.304-219.880727C966.469818 147.642182 871.982545 57.157818 755.898182 47.755636c-43.380364-3.723636-69.632 1.210182-104.075637 16.942546-6.330182 3.072-29.975273 20.666182-13.963636 45.893818 9.495273 12.474182 20.386909 26.996364 51.013818 16.290909 26.065455-8.843636 40.96-7.540364 73.448728-2.513454 72.704 11.357091 130.885818 69.818182 140.38109 141.963636 12.753455 96.721455-60.043636 179.665455-154.530909 186.554182-13.312 3.723636-20.293818 18.897455-22.341818 31.464727-1.861818 13.777455 3.258182 42.077091 12.846546 43.938909 165.981091 1.303273 301.335273 134.423273 301.893818 297.797818 0 19.456 14.056727 36.398545 33.233454 38.912A37.981091 37.981091 0 0 0 1117.090909 827.950545c-0.651636-156.392727-98.304-290.257455-236.823273-346.763636z')
const redis = defs.append('g')
.attr('id', 'redis')
.attr('transform', 'scale(0.042)')
redis.append('path')
.attr('d', 'M632.661333 774.4c-65.194667 33.962667-101.12 33.621333-152.746666 8.96-51.2-24.576-479.573333-203.52-479.573334-203.52v129.706667c0 11.264 15.701333 23.04 44.714667 36.949333 58.538667 28.074667 383.658667 159.146667 434.773333 183.893333 51.2 24.576 87.466667 24.746667 152.746667-8.96 65.109333-34.048 370.346667-159.317333 429.312-190.293333 30.037333-15.616 43.264-27.904 43.264-38.826667v-128h-0.085333c-0.170667-0.170667-407.466667 175.957333-472.405334 210.090667z')
redis.append('path')
.attr('d', 'M632.661333 592.213333c-65.194667 33.962667-101.12 33.536-152.746666 8.96-51.2-24.746667-479.573333-203.776-479.573334-203.776v129.706667c0 11.178667 15.701333 22.954667 44.714667 36.864 58.538667 28.16 383.658667 159.317333 434.773333 184.064 51.2 24.576 87.466667 24.746667 152.746667-8.96 65.109333-34.048 370.346667-159.317333 429.312-190.293333 30.037333-15.616 43.264-27.904 43.264-38.826667v-128h-0.085333c-0.170667 0-407.466667 176.128-472.405334 210.176z')
redis.append('path')
.attr('d', 'M1105.322667 211.114667c0.512-11.178667-14.421333-21.162667-43.776-31.914667C1004.032 158.037333 700.501333 37.290667 642.304 16.042667c-58.282667-21.333333-81.92-20.309333-150.186667 4.010666S100.693333 171.349333 43.093333 193.877333c-29.013333 11.264-43.093333 21.930667-42.24 33.28V226.986667v127.658666S428.885333 535.04 480.426667 559.530667c51.2 24.661333 87.381333 24.746667 152.661333-8.96 65.024-34.218667 472.661333-213.333333 472.661333-213.333334l-0.426666-126.122666z m-143.018667 3.413333L794.453333 280.746667l-151.296-59.818667 167.594667-66.304 151.552 59.904z m-310.016 62.890667l-77.568 113.493333-178.517333-74.069333 256-39.424z m-134.485333-172.373334l-24.746667-45.738666 77.312 30.122666 72.618667-23.893333-19.712 47.104 74.24 27.904-95.829334 9.813333-21.504 51.797334-34.56-57.685334-110.506666-9.728 82.773333-29.781333z m-190.634667 64.170667c75.605333 0 136.874667 23.637333 136.874667 53.077333 0 29.184-61.269333 53.077333-136.874667 53.077334-75.605333 0-136.96-23.637333-136.96-53.077334 0.170667-29.013333 61.44-53.077333 136.96-53.077333z')
}
initBox() {
this.drawBox();
this.drawBoxText();
}
// 初始化鏈接線
initLink() {
this.drawLinkLine();
this.drawLinkText();
}
// 初始化節(jié)點
initNode() {
var self = this;
// 節(jié)點容器
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 (d) {
self.currentNode = d
self.showDialog = true
})
// 節(jié)點背景默認覆蓋層
this.nodes.append('circle')
.attr('r', symbolSize / 2 + padding)
.attr('class', 'node-bg')
.style('opacity', 0.0); // 設(shè)置透明背景
// 節(jié)點圖標
this.drawNodeSymbol();
// 節(jié)點標題
this.drawNodeTitle();
// 節(jié)點其他說明
// this.drawNodeOther();
// this.drawNodeCode();
}
// 畫節(jié)點語言標識
// 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);
// }
// 畫節(jié)點圖標
drawNodeSymbol() {
this.nodeUse && this.nodes.selectAll('use').remove();
this.nodeUse = this.nodes.append('use');
this.nodeUse
.attr('xlink:href', function (d) {
return '#' + d.type
})
.attr('fill', function (d) {
return colors[d.color] || colors[0]
})
.attr('x', function () {
return -20
})
.attr('y', function () {
return -20
})
let run = () => {
this.nodeUse.filter(node => node.color === 'danger')
.transition()
.duration(300)
.style('fill', boxBg)
.transition()
.duration(300)
.style('fill', function (d) {
return colors[d.color] || colors[0]
})
.on('end', run)
}
run()
}
// 畫節(jié)點標題
drawNodeTitle() {
this.nodeTitle && this.nodes.selectAll('text').remove();
this.nodeTitle = this.nodes.append('text');
this.nodeTitle
.attr('class', 'node-title')
.text(function (d) {
return d.name;
})
.attr('dy', 35)
}
// 畫節(jié)點右側(cè)信息
drawNodeOther() {
this.nodes.filter(node => node.other !== undefined)
.append('circle')
.attr('cx', 35)
.attr('cy', -3)
.attr('r', 5)
.attr('fill', colors.primary);
this.nodes.filter(node => node.other !== undefined)
.append('text')
.attr('dx', 45)
.attr('dy', 0)
.text(d => d.other.num)
this.nodes.filter(node => node.other !== undefined)
.append('circle')
.attr('cx', 35)
.attr('cy', 7)
.attr('r', 5)
.attr('fill', colors.danger);
this.nodes.filter(node => node.other !== undefined)
.append('text')
.attr('dx', 45)
.attr('dy', 10)
.text(d => d.other.error)
}
// 畫節(jié)點鏈接線
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')
.style('storke-width', '0.2') // 邊框?qū)挾? .attr('stroke', lineColor)
.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 source = data.find(f => f.id === d.source)
let target = data.find(f => f.id === d.target)
if (source && target) {
let sx = source.x; // data[d.source].x;
let tx = target.x; // data[d.target].x;
let sy = source.y; // data[d.source].y;
let ty = target.y; // 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('class', 'linetext')
.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.find(f => f.id === link.source); // data[link.source];
let t = data.find(f => f.id === link.target); // data[link.target];
if (s && t) {
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 + ')'
}
}
}
drawBox() {
if (this.lineBoxGroup) {
this.lineBoxGroup.selectAll('.box')
} else {
this.lineBoxGroup = this.container.append('g')
this.lineBoxGroup.selectAll('.box')
.data(this.boxs)
.enter()
.append('rect')
.attr('class', 'box')
.attr('x', box => box.x)
.attr('y', box => box.y)
.attr('width', box => box.width)
.attr('height', box => box.height)
.attr('fill', boxBg)
.style('storke-width', '0.2') // 邊框?qū)挾? .style('stroke', boxBorder)
.attr(
'id', (box, i) => 'box-' + i
)
.on('click', () => { alert() })
}
}
drawBoxText () {
this.boxTextGroup = this.container.append('g')
this.boxTexts = this.boxTextGroup
.selectAll('g')
.data(this.boxs.filter(t => t.text !== undefined))
.enter()
.append('text')
.attr('class', 'boxText')
.attr('x', function(d, i) { // 每個矩形的起始x坐標
return d.textPosition === 'right' ? (d.x + d.width - 30) : (d.x + 30)
})
.attr('y', function(d, i) {
return d.y + 20
}).text(function(d) { // 添加文字描述
return d['text'];
})
.style('font-size', fontSize)// 設(shè)置文字大小
}
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 + ')')
}
// 重畫
redraw(option) {
this.data = option.data;
this.edges = option.edges;
this.boxs = option.boxs;
let update = this.nodes.data(this.data)
update.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')';
})
// 節(jié)點圖標
this.drawNodeSymbol();
// 節(jié)點標題
this.drawNodeTitle();
this.update()
}
downloadImg(name = 'topo', type = 'png') { // 將當前canvas轉(zhuǎn)換為png圖片
var serializer = new XMLSerializer();
var source = serializer.serializeToString(this.svg.node());
source = '<?xml version="1.0" standalone="no"?>\r\n' + source;
var url = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source);
var image = new Image();
image.src = url;
let canvas = document.createElement('canvas');
canvas.width = 1600;
canvas.height = 800;
var context = canvas.getContext('2d');
context.fillStyle = '#fff'; // #fff設(shè)置保存后的PNG 是白色的
context.fillRect(0, 0, 10000, 10000);
image.onload = function() {
context.drawImage(image, 0, 0); // 圖片要完全loaded后才能draw,否則火狐下的報錯'Component is not available'
var a = document.createElement('a');
document.body.appendChild(a);
a.download = `${name + new Date().toLocaleString()}.${type}`
a.href = canvas.toDataURL(`image/${type}`)
var evt = new MouseEvent('click', { view: window, bubbles: true, cancelable: true });
a.dispatchEvent(evt);
document.body.removeChild(a);
}
}
}
export class Node {
constructor (id, type, name, status, x, y) {
this.id = id || uniqueId()
this.name = name
this.type = type
this.color = status
this.x = x
this.y = y
}
}
index.vue
<template>
<div class="main-container">
<el-row class="main-top">
<el-col :span="12">
<div class="top-left">
<el-select
v-model="refresh"
size="small"
placeholder=""
:style="isZh ? 'width: 100px': ''"
@change="changeRefresh"
>
<el-option
v-for="item in refreshs"
:key="item.value"
:label="$t(item.i18nKey)"
:value="item.value">
</el-option>
</el-select>
</div>
</el-col>
<el-col :span="12">
<div class="top-right">
<template v-for="item of Object.keys(state)">
<span :key="item + '_dot'" class="dot" :class="state[item]"></span>
<span :key="item + '_text'" class="text" :class="state[item]">
{{ $t(`topo.${state[item]}`) }}
</span>
</template>
<el-button type="primary" size="small" @click="exportPNG">
{{ $t('btn.png') }}
</el-button>
</div>
</el-col>
</el-row>
<div class="svg-container">
<svg
:id="docId"
class="topo"
width="1600"
height="800"
/>
</div>
</div>
</template>
<script>
import locale from '@/i18n/locale.mixin'
import { Topo, Node } from './topo'
// import detail from './detail'
export default {
components: {
// detail
},
mixins: [locale],
data () {
return {
topo: {},
topoData: {
data: [],
edges: [],
boxs: []
},
docId: 'topo',
state: {
'NORMAL': 'primary',
'WARN': 'warning',
'BREAK': 'danger'
},
refresh: 60,
refreshs: [
{ value: 0, i18nKey: 'topo.refreshNone' },
{ value: 10, i18nKey: 'topo.refresh10' },
{ value: 30, i18nKey: 'topo.refresh30' },
{ value: 60, i18nKey: 'topo.refresh60' },
{ value: 120, i18nKey: 'topo.refresh120' }
],
timer: ''
}
},
created () {
},
async mounted () {
await this.initData()
this.topo = new Topo('#' + this.docId, this.topoData)
this.topo.render();
// this.timer = setInterval(this.update, this.refresh * 1000);
},
beforeDestroy() {
clearInterval(this.timer);
},
methods: {
initData (refresh = false) {
const x = 50;
const y = 50;
// 節(jié)點數(shù)據(jù)
let data = require('./topoNode.json');
refresh && this.topoData.data.splice(0, this.topoData.data.length);
data.forEach(item => {
let node = new Node(
item.id,
item.description ? item.description : 'innerUser',
item.name,
item.state ? item.state : 'primary',
x * item.positionX,
y * item.positionY
)
this.topoData.data.push(node)
})
// 連線數(shù)據(jù)
refresh && this.topoData.edges.splice(0, this.topoData.edges.length);
this.topoData.edges = require('./topoEdge.json');
},
changeRefresh(v) {
if (v > 0) {
this.timer && clearInterval(this.timer);
this.timer = setInterval(this.update, v * 1000);
this.update()
} else {
clearInterval(this.timer);
}
},
async update() {
// TODO
await this.initData(true)
this[this.docId].redraw(this.topoData)
},
exportPNG() {
this[this.docId].downloadImg()
}
}
}
</script>
<style>
.svg-container {
border:1px solid #ccc;
height: calc(100vh - 180px); /*垂直 500 < 550*/
overflow:auto;
}
.topo{
width: 100%;
min-height: 500px;
height: 800px;
overflow:auto;
user-select: none;
}
.topo text{
font-size:10px;/*和js里保持一致*/
fill:#1A2C3F;
text-anchor: middle;
}
.topo .node-other{
text-anchor: start;
}
.topo .node-title{
font-size: 14px;
}
.topo .node-code circle{
fill:#3F86F5;
}
.topo .node-code text{
fill:#fff;
}
.topo .arrow{
fill:#E4E8ED;
}
.main-top .title-box {
line-height: 16px;
}
.main-top .top-left, .main-top .top-right {
line-height: 32px;
}
.main-top .top-right {
text-align: right;
}
.main-top .top-right .dot {
top: 0;
margin-left: 20px;
}
.main-top .dot.primary {
background-color: #409EFF;
}
.main-top .primary {
color: #409EFF;
}
.main-top .dot.warning {
background-color: #E6A23C;
}
.main-top .warning {
color: #E6A23C;
}
.main-top .dot.danger {
background-color: #F56C6C;
}
.main-top .danger {
color: #F56C6C;
}
.main-top .top-right .text {
margin-left: 5px;
font-weight: 700;
}
.dot {
position: relative;
top: -1px;
display: inline-block;
width: 10px;
height: 10px;
margin-right: 2px;
border-radius: 8px;
background-color: #1890ff;
}
</style>
topoNode.json
[
{
"id": 1,
"name": "用戶",
"description": "user",
"positionX": 2,
"positionY": 2
},
{
"id": 2,
"name": "云",
"description": "cloud",
"positionX": 2,
"positionY": 4
},
{
"id": 3,
"name": "DNS",
"description": "dns",
"positionX": 3,
"positionY": 4
},
{
"id": 4,
"name": "四層交換機",
"description": "switch",
"state": "danger",
"positionX": 8,
"positionY": 4
},
{
"id": 5,
"name": "交換機",
"description": "switch",
"positionX": 2,
"positionY": 6
},
{
"id": 6,
"name": "交換機",
"description": "switch",
"positionX": 4,
"positionY": 6
},
{
"id": 7,
"name": "交換機",
"description": "switch",
"positionX": 6,
"positionY": 6
},
{
"id": 8,
"name": "交換機",
"description": "switch",
"positionX": 8,
"positionY": 6
},
{
"id": 9,
"name": "交換機",
"description": "switch",
"positionX": 10,
"positionY": 6
},
{
"id": 10,
"name": "交換機",
"description": "switch",
"positionX": 12,
"positionY": 6
},
{
"id": 11,
"name": "工作站",
"description": "OpenResty",
"positionX": 2,
"positionY": 8
},
{
"id": 12,
"name": "工作站",
"description": "OpenResty",
"positionX": 4,
"positionY": 8
},
{
"id": 13,
"name": "工作站",
"description": "OpenResty",
"positionX": 6,
"positionY": 8
},
{
"id": 14,
"name": "工作站",
"description": "OpenResty",
"positionX": 8,
"positionY": 8
},
{
"id": 15,
"name": "工作站",
"description": "OpenResty",
"positionX": 10,
"positionY": 8
},
{
"id": 16,
"name": "工作站",
"description": "OpenResty",
"positionX": 12,
"positionY": 8
},
{
"id": 17,
"name": "服務(wù)器",
"description": "gateway",
"positionX": 11,
"positionY": 4
},
{
"id": 18,
"name": "",
"description": "gateway",
"positionX": 11.5,
"positionY": 4
}
]
topoEdge.json
[
{
"source": 1,
"target": 2
},
{
"source": 2,
"target": 4
},
{
"source": 4,
"target": 5
},
{
"source": 4,
"target": 5
},
{
"source": 4,
"target": 6
},
{
"source": 4,
"target": 7
},
{
"source": 4,
"target": 8
},
{
"source": 4,
"target": 9
},
{
"source": 4,
"target": 10
},
{
"source": 5,
"target": 11
},
{
"source": 6,
"target": 12
},
{
"source": 7,
"target": 13
},
{
"source": 8,
"target": 14
},
{
"source": 9,
"target": 15
},
{
"source": 10,
"target": 16
},
{
"source": 4,
"target": 17
}
]