mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-14 09:00:50 +00:00
update
This commit is contained in:
parent
5852ea293a
commit
bc2d29d728
@ -92,17 +92,24 @@ export const networkProfilingStore = defineStore({
|
|||||||
}
|
}
|
||||||
return prev;
|
return prev;
|
||||||
}, []);
|
}, []);
|
||||||
calls = calls.map((d: any) => {
|
const param = {} as any;
|
||||||
d.sourceId = d.source;
|
calls = data.calls.reduce((prev: (Call | any)[], next: Call | any) => {
|
||||||
d.targetId = d.target;
|
if (param[next.targetId + next.sourceId]) {
|
||||||
d.source = d.sourceObj;
|
next.lowerArc = true;
|
||||||
d.target = d.targetObj;
|
}
|
||||||
delete d.sourceObj;
|
param[next.sourceId + next.targetId] = true;
|
||||||
delete d.targetObj;
|
next.sourceId = next.source;
|
||||||
return d;
|
next.targetId = next.target;
|
||||||
});
|
next.source = next.sourceObj;
|
||||||
|
next.target = next.targetObj;
|
||||||
|
delete next.sourceObj;
|
||||||
|
delete next.targetObj;
|
||||||
|
prev.push(next);
|
||||||
|
return prev;
|
||||||
|
}, []);
|
||||||
this.calls = calls;
|
this.calls = calls;
|
||||||
this.nodes = data.nodes;
|
this.nodes = data.nodes;
|
||||||
|
console.log(calls);
|
||||||
},
|
},
|
||||||
async createNetworkTask(param: {
|
async createNetworkTask(param: {
|
||||||
serviceId: string;
|
serviceId: string;
|
||||||
|
@ -23,31 +23,7 @@ export const linkElement = (graph: any) => {
|
|||||||
.attr("class", "topo-call")
|
.attr("class", "topo-call")
|
||||||
.attr("marker-end", "url(#arrow)")
|
.attr("marker-end", "url(#arrow)")
|
||||||
.attr("stroke", "#97B0F8")
|
.attr("stroke", "#97B0F8")
|
||||||
.attr("d", (d: Call) => {
|
.attr("d", (d: Call) => linkPath(d));
|
||||||
const controlPos = computeControlPoint(
|
|
||||||
[d.source.x, d.source.y - 5],
|
|
||||||
[d.target.x, d.target.y - 5],
|
|
||||||
0.5
|
|
||||||
);
|
|
||||||
if (d.lowerArc) {
|
|
||||||
controlPos[1] = -controlPos[1] - 10;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
"M" +
|
|
||||||
d.source.x +
|
|
||||||
" " +
|
|
||||||
(d.source.y - 5) +
|
|
||||||
" " +
|
|
||||||
"Q" +
|
|
||||||
controlPos[0] +
|
|
||||||
" " +
|
|
||||||
controlPos[1] +
|
|
||||||
" " +
|
|
||||||
d.target.x +
|
|
||||||
" " +
|
|
||||||
(d.target.y - 5)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return linkEnter;
|
return linkEnter;
|
||||||
};
|
};
|
||||||
export const anchorElement = (graph: any, funcs: any, tip: any) => {
|
export const anchorElement = (graph: any, funcs: any, tip: any) => {
|
||||||
@ -77,13 +53,7 @@ export const anchorElement = (graph: any, funcs: any, tip: any) => {
|
|||||||
return p[1] - 13;
|
return p[1] - 13;
|
||||||
})
|
})
|
||||||
.attr("xlink:href", (d: Call) => {
|
.attr("xlink:href", (d: Call) => {
|
||||||
const types = [...d.sourceComponents, ...d.targetComponents];
|
return getAnchor(d);
|
||||||
if (types.includes("tcp") || types.includes("http")) {
|
|
||||||
return icons.HTTPDARK;
|
|
||||||
}
|
|
||||||
if (types.includes("https") || types.includes("tls")) {
|
|
||||||
return icons.HTTPS;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return linkEnter;
|
return linkEnter;
|
||||||
};
|
};
|
||||||
@ -135,13 +105,14 @@ function quadraticBezier(
|
|||||||
const y = (1 - t) * (1 - t) * ps.y + 2 * t * (1 - t) * pc.y + t * t * pe.y;
|
const y = (1 - t) * (1 - t) * ps.y + 2 * t * (1 - t) * pc.y + t * t * pe.y;
|
||||||
return [x, y];
|
return [x, y];
|
||||||
}
|
}
|
||||||
function getMidpoint(d: Call) {
|
export function getMidpoint(d: Call) {
|
||||||
const controlPos = computeControlPoint(
|
const controlPos = computeControlPoint(
|
||||||
[d.source.x, d.source.y],
|
[d.source.x, d.source.y],
|
||||||
[d.target.x, d.target.y],
|
[d.target.x, d.target.y],
|
||||||
0.5
|
0.5
|
||||||
);
|
);
|
||||||
if (d.lowerArc) {
|
if (d.lowerArc) {
|
||||||
|
console.log(true);
|
||||||
controlPos[1] = -controlPos[1];
|
controlPos[1] = -controlPos[1];
|
||||||
}
|
}
|
||||||
const p = quadraticBezier(
|
const p = quadraticBezier(
|
||||||
@ -152,3 +123,37 @@ function getMidpoint(d: Call) {
|
|||||||
);
|
);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
export function linkPath(d: Call) {
|
||||||
|
const controlPos = computeControlPoint(
|
||||||
|
[d.source.x, d.source.y - 5],
|
||||||
|
[d.target.x, d.target.y - 5],
|
||||||
|
0.5
|
||||||
|
);
|
||||||
|
if (d.lowerArc) {
|
||||||
|
controlPos[1] = -controlPos[1] - 10;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
"M" +
|
||||||
|
d.source.x +
|
||||||
|
" " +
|
||||||
|
(d.source.y - 5) +
|
||||||
|
" " +
|
||||||
|
"Q" +
|
||||||
|
controlPos[0] +
|
||||||
|
" " +
|
||||||
|
controlPos[1] +
|
||||||
|
" " +
|
||||||
|
d.target.x +
|
||||||
|
" " +
|
||||||
|
(d.target.y - 5)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function getAnchor(d: Call) {
|
||||||
|
const types = [...d.sourceComponents, ...d.targetComponents];
|
||||||
|
if (types.includes("tcp") || types.includes("http")) {
|
||||||
|
return icons.HTTPDARK;
|
||||||
|
}
|
||||||
|
if (types.includes("https") || types.includes("tls")) {
|
||||||
|
return icons.HTTPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,7 +13,89 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div ref="chart" class="process-topo"></div>
|
<div ref="chart" class="process-topo">
|
||||||
|
<svg
|
||||||
|
class="process-svg"
|
||||||
|
:width="width"
|
||||||
|
:height="height"
|
||||||
|
@click="clickTopology"
|
||||||
|
>
|
||||||
|
<g class="svg-graph" :transform="`translate(${diff[0]}, ${diff[1]})`">
|
||||||
|
<g class="hex-polygon">
|
||||||
|
<path
|
||||||
|
:d="getHexPolygonVertices()"
|
||||||
|
stroke="#D5DDF6"
|
||||||
|
stroke-width="2"
|
||||||
|
fill="none"
|
||||||
|
/>
|
||||||
|
<text :x="0" :y="radius - 15" fill="#000" text-anchor="middle">
|
||||||
|
{{ selectorStore.currentPod.label }}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g class="nodes">
|
||||||
|
<g v-for="(node, index) in nodeList" :key="index">
|
||||||
|
<image
|
||||||
|
:href="icons.CUBE"
|
||||||
|
style="cursor: 'move'"
|
||||||
|
width="35"
|
||||||
|
height="35"
|
||||||
|
:x="node.x - 15"
|
||||||
|
:y="node.y - 15"
|
||||||
|
/>
|
||||||
|
<text :x="node.x" :y="node.y + 28" fill="#000" text-anchor="middle">
|
||||||
|
{{
|
||||||
|
node.name.length > 10
|
||||||
|
? `${node.name.substring(0, 10)}...`
|
||||||
|
: node.name
|
||||||
|
}}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="calls">
|
||||||
|
<path
|
||||||
|
v-for="(call, index) in networkProfilingStore.calls"
|
||||||
|
:key="index"
|
||||||
|
class="topo-call"
|
||||||
|
markerEnd="url(#arrow)"
|
||||||
|
stroke="#97B0F8"
|
||||||
|
:d="linkPath(call)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g class="anchors">
|
||||||
|
<image
|
||||||
|
v-for="(call, index) in networkProfilingStore.calls"
|
||||||
|
:key="index"
|
||||||
|
class="topo-line-anchor"
|
||||||
|
:href="getAnchor(call)"
|
||||||
|
width="15"
|
||||||
|
height="15"
|
||||||
|
:x="getMidpoint(call)[0] - 8"
|
||||||
|
:y="getMidpoint(call)[1] - 13"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<g class="arrows">
|
||||||
|
<defs
|
||||||
|
v-for="(call, index) in networkProfilingStore.calls"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<marker
|
||||||
|
id="arrow"
|
||||||
|
class="topo-line-arrow"
|
||||||
|
markerUnits="strokeWidth"
|
||||||
|
markerWidth="8"
|
||||||
|
markerHeight="8"
|
||||||
|
viewBox="0 0 12 12"
|
||||||
|
refX="10"
|
||||||
|
refY="6"
|
||||||
|
orient="auto"
|
||||||
|
>
|
||||||
|
<path d="M2,2 L10,6 L2,10 L6,6 L2,2" fill="#97B0F8" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
<el-popover placement="bottom" :width="295" trigger="click">
|
<el-popover placement="bottom" :width="295" trigger="click">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<div
|
<div
|
||||||
@ -40,8 +122,7 @@ import { useNetworkProfilingStore } from "@/store/modules/network-profiling";
|
|||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import d3tip from "d3-tip";
|
import d3tip from "d3-tip";
|
||||||
import { linkElement, anchorElement, arrowMarker } from "./Graph/linkProcess";
|
import { linkPath, getAnchor, getMidpoint } from "./Graph/linkProcess";
|
||||||
import nodeElement from "./Graph/nodeProcess";
|
|
||||||
import { Call } from "@/types/topology";
|
import { Call } from "@/types/topology";
|
||||||
import zoom from "../../components/utils/zoom";
|
import zoom from "../../components/utils/zoom";
|
||||||
import { ProcessNode } from "@/types/ebpf";
|
import { ProcessNode } from "@/types/ebpf";
|
||||||
@ -52,6 +133,7 @@ import getDashboard from "@/hooks/useDashboardsSession";
|
|||||||
import { Layout } from "./Graph/layout";
|
import { Layout } from "./Graph/layout";
|
||||||
import TimeLine from "./TimeLine.vue";
|
import TimeLine from "./TimeLine.vue";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import icons from "@/assets/img/icons";
|
||||||
|
|
||||||
/*global Nullable, defineProps */
|
/*global Nullable, defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -67,7 +149,6 @@ const selectorStore = useSelectorStore();
|
|||||||
const networkProfilingStore = useNetworkProfilingStore();
|
const networkProfilingStore = useNetworkProfilingStore();
|
||||||
const height = ref<number>(100);
|
const height = ref<number>(100);
|
||||||
const width = ref<number>(100);
|
const width = ref<number>(100);
|
||||||
const svg = ref<Nullable<any>>(null);
|
|
||||||
const chart = ref<Nullable<HTMLDivElement>>(null);
|
const chart = ref<Nullable<HTMLDivElement>>(null);
|
||||||
const tip = ref<Nullable<HTMLDivElement>>(null);
|
const tip = ref<Nullable<HTMLDivElement>>(null);
|
||||||
const graph = ref<any>(null);
|
const graph = ref<any>(null);
|
||||||
@ -91,7 +172,7 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
svg.value = d3.select(chart.value).append("svg").attr("class", "process-svg");
|
// svg.value = d3.select(chart.value).append("svg").attr("class", "process-svg");
|
||||||
if (!networkProfilingStore.nodes.length) {
|
if (!networkProfilingStore.nodes.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -106,38 +187,14 @@ function drawGraph() {
|
|||||||
};
|
};
|
||||||
height.value = (dom.height || 40) - 20;
|
height.value = (dom.height || 40) - 20;
|
||||||
width.value = dom.width;
|
width.value = dom.width;
|
||||||
svg.value.attr("height", height.value).attr("width", width.value);
|
}
|
||||||
tip.value = (d3tip as any)().attr("class", "d3-tip").offset([-8, 0]);
|
|
||||||
diff.value[0] = (dom.width - radius * 2) / 2 + radius;
|
function clickTopology(event: any) {
|
||||||
graph.value = svg.value
|
event.stopPropagation();
|
||||||
.append("g")
|
event.preventDefault();
|
||||||
.attr("class", "svg-graph")
|
networkProfilingStore.setNode(null);
|
||||||
.attr("transform", `translate(${diff.value[0]}, ${diff.value[1]})`);
|
networkProfilingStore.setLink(null);
|
||||||
graph.value.call(tip.value);
|
dashboardStore.selectWidget(props.config);
|
||||||
node.value = graph.value
|
|
||||||
.append("g")
|
|
||||||
.attr("class", "nodes")
|
|
||||||
.selectAll(".topo-node");
|
|
||||||
link.value = graph.value
|
|
||||||
.append("g")
|
|
||||||
.attr("class", "calls")
|
|
||||||
.selectAll(".topo-call");
|
|
||||||
anchor.value = graph.value
|
|
||||||
.append("g")
|
|
||||||
.attr("class", "anchors")
|
|
||||||
.selectAll(".topo-line-anchor");
|
|
||||||
arrow.value = graph.value
|
|
||||||
.append("g")
|
|
||||||
.attr("class", "arrows")
|
|
||||||
.selectAll(".topo-line-arrow");
|
|
||||||
svg.value.call(zoom(d3, graph.value, diff.value));
|
|
||||||
svg.value.on("click", (event: any) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
networkProfilingStore.setNode(null);
|
|
||||||
networkProfilingStore.setLink(null);
|
|
||||||
dashboardStore.selectWidget(props.config);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hexGrid(n = 1, radius = 1, origin = [0, 0]) {
|
function hexGrid(n = 1, radius = 1, origin = [0, 0]) {
|
||||||
@ -179,17 +236,8 @@ function getCirclePoint(radius: number, p = 1) {
|
|||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
function createLayout() {
|
|
||||||
if (!node.value || !link.value) {
|
function getHexPolygonVertices() {
|
||||||
return;
|
|
||||||
}
|
|
||||||
const dom: any = (chart.value && chart.value.getBoundingClientRect()) || {
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
};
|
|
||||||
if (isNaN(dom.width) || dom.width < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const p = {
|
const p = {
|
||||||
count: 1,
|
count: 1,
|
||||||
radius, // layout hexagons radius 300
|
radius, // layout hexagons radius 300
|
||||||
@ -202,20 +250,21 @@ function createLayout() {
|
|||||||
}
|
}
|
||||||
const linePath = d3.line();
|
const linePath = d3.line();
|
||||||
linePath.curve(d3.curveLinearClosed);
|
linePath.curve(d3.curveLinearClosed);
|
||||||
const hexPolygon = graph.value.append("g").attr("class", "hex-polygon");
|
return linePath(vertices) || "";
|
||||||
hexPolygon
|
}
|
||||||
.append("path")
|
function createLayout() {
|
||||||
.attr("d", linePath(vertices))
|
const dom: any = (chart.value && chart.value.getBoundingClientRect()) || {
|
||||||
.attr("stroke", "#D5DDF6")
|
width: 0,
|
||||||
.attr("stroke-width", 2)
|
height: 0,
|
||||||
.style("fill", "none");
|
};
|
||||||
hexPolygon
|
if (isNaN(dom.width) || dom.width < 1) {
|
||||||
.append("text")
|
return;
|
||||||
.attr("fill", "#000")
|
}
|
||||||
.attr("text-anchor", "middle")
|
const p = {
|
||||||
.attr("x", 0)
|
count: 1,
|
||||||
.attr("y", p.radius - 15)
|
radius, // layout hexagons radius 300
|
||||||
.text(() => selectorStore.currentPod.label);
|
};
|
||||||
|
const origin = [0, 0];
|
||||||
const nodeArr = networkProfilingStore.nodes.filter(
|
const nodeArr = networkProfilingStore.nodes.filter(
|
||||||
(d: ProcessNode) => d.isReal || d.name === "UNKNOWN_LOCAL"
|
(d: ProcessNode) => d.isReal || d.name === "UNKNOWN_LOCAL"
|
||||||
);
|
);
|
||||||
@ -291,73 +340,6 @@ function createLayout() {
|
|||||||
outNodes[v].y = pointArr[v][1];
|
outNodes[v].y = pointArr[v][1];
|
||||||
}
|
}
|
||||||
nodeList.value = [...nodeArr, ...outNodes];
|
nodeList.value = [...nodeArr, ...outNodes];
|
||||||
drawTopology(nodeList.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawTopology(nodeArr: any[]) {
|
|
||||||
node.value = node.value.data(nodeArr, (d: ProcessNode) => d.id);
|
|
||||||
node.value.exit().remove();
|
|
||||||
node.value = nodeElement(
|
|
||||||
d3,
|
|
||||||
node.value.enter(),
|
|
||||||
{
|
|
||||||
tipHtml: (data: ProcessNode) => {
|
|
||||||
return ` <div class="mb-5"><span class="grey">name: </span>${data.name}</div>`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tip.value
|
|
||||||
).merge(node.value);
|
|
||||||
// line element
|
|
||||||
const obj = {} as any;
|
|
||||||
const calls = networkProfilingStore.calls.reduce(
|
|
||||||
(
|
|
||||||
prev: (Call & { targetId: string; sourceId: string })[],
|
|
||||||
next: Call & { targetId: string; sourceId: string }
|
|
||||||
) => {
|
|
||||||
if (obj[next.targetId + next.sourceId]) {
|
|
||||||
next.lowerArc = true;
|
|
||||||
}
|
|
||||||
obj[next.sourceId + next.targetId] = true;
|
|
||||||
prev.push(next);
|
|
||||||
return prev;
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
link.value = link.value.data(calls, (d: Call) => d.id);
|
|
||||||
link.value.exit().remove();
|
|
||||||
link.value = linkElement(link.value.enter()).merge(link.value);
|
|
||||||
anchor.value = anchor.value.data(calls, (d: Call) => d.id);
|
|
||||||
anchor.value.exit().remove();
|
|
||||||
anchor.value = anchorElement(
|
|
||||||
anchor.value.enter(),
|
|
||||||
{
|
|
||||||
handleLinkClick: handleLinkClick,
|
|
||||||
tipHtml: (data: Call) => {
|
|
||||||
const types = [...data.sourceComponents, ...data.targetComponents];
|
|
||||||
let l = "TCP";
|
|
||||||
if (types.includes("https")) {
|
|
||||||
l = "HTTPS";
|
|
||||||
}
|
|
||||||
if (types.includes("http")) {
|
|
||||||
l = "HTTP";
|
|
||||||
}
|
|
||||||
if (types.includes("tls")) {
|
|
||||||
l = "TLS";
|
|
||||||
}
|
|
||||||
const html = `<div><span class="grey">${t(
|
|
||||||
"detectPoint"
|
|
||||||
)}: </span>${data.detectPoints.join(" | ")}</div>
|
|
||||||
<div><span class="grey">Type: </span>${l}</div>`;
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tip.value
|
|
||||||
).merge(anchor.value);
|
|
||||||
// arrow marker
|
|
||||||
arrow.value = arrow.value.data(calls, (d: Call) => d.id);
|
|
||||||
arrow.value.exit().remove();
|
|
||||||
arrow.value = arrowMarker(arrow.value.enter()).merge(arrow.value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function shuffleArray(array: number[][]) {
|
function shuffleArray(array: number[][]) {
|
||||||
@ -441,7 +423,7 @@ function resize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function freshNodes() {
|
async function freshNodes() {
|
||||||
svg.value.selectAll(".svg-graph").remove();
|
d3.select("svg-graph").remove();
|
||||||
if (!networkProfilingStore.nodes.length) {
|
if (!networkProfilingStore.nodes.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user