mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-12 15:52:57 +00:00
feat: update layout
This commit is contained in:
parent
9d01283739
commit
26d0a8d681
@ -136,7 +136,7 @@ limitations under the License. -->
|
|||||||
height="600px"
|
height="600px"
|
||||||
>
|
>
|
||||||
<div class="hierarchy-related">
|
<div class="hierarchy-related">
|
||||||
<Map :config="config" />
|
<hierarchy-map :config="config" />
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@ -162,10 +162,10 @@ limitations under the License. -->
|
|||||||
import { aggregation } from "@/hooks/useMetricsProcessor";
|
import { aggregation } from "@/hooks/useMetricsProcessor";
|
||||||
import icons from "@/assets/img/icons";
|
import icons from "@/assets/img/icons";
|
||||||
import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor";
|
import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor";
|
||||||
import { layout, circleIntersection, computeCallPos } from "./utils/layout";
|
import { layout, computeLevels, changeNode } from "./utils/layout";
|
||||||
import zoom from "../../components/utils/zoom";
|
import zoom from "../../components/utils/zoom";
|
||||||
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
|
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
import Map from "./Map.vue";
|
import HierarchyMap from "./HierarchyMap.vue";
|
||||||
|
|
||||||
/*global Nullable, defineProps */
|
/*global Nullable, defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -194,7 +194,7 @@ limitations under the License. -->
|
|||||||
const topologyLayout = ref<any>({});
|
const topologyLayout = ref<any>({});
|
||||||
const tooltip = ref<Nullable<any>>(null);
|
const tooltip = ref<Nullable<any>>(null);
|
||||||
const graphWidth = ref<number>(100);
|
const graphWidth = ref<number>(100);
|
||||||
const currentNode = ref<Nullable<Node>>();
|
const currentNode = ref<Nullable<Node>>(null);
|
||||||
const diff = computed(() => [(width.value - graphWidth.value - 130) / 2, 100]);
|
const diff = computed(() => [(width.value - graphWidth.value - 130) / 2, 100]);
|
||||||
const hierarchyRelated = ref<boolean>(false);
|
const hierarchyRelated = ref<boolean>(false);
|
||||||
const radius = 8;
|
const radius = 8;
|
||||||
@ -253,107 +253,19 @@ limitations under the License. -->
|
|||||||
setNodeTools(settings.value.nodeDashboard);
|
setNodeTools(settings.value.nodeDashboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeLevels(calls: Call[], nodeList: Node[], levels: any[]) {
|
|
||||||
const node = findMostFrequent(calls);
|
|
||||||
const nodes = JSON.parse(JSON.stringify(nodeList)).sort((a: Node, b: Node) => {
|
|
||||||
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (a.name.toLowerCase() > b.name.toLowerCase()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
const index = nodes.findIndex((n: Node) => n.type === "USER");
|
|
||||||
let key = index;
|
|
||||||
if (index < 0) {
|
|
||||||
key = nodes.findIndex((n: Node) => n.id === node.id);
|
|
||||||
}
|
|
||||||
levels.push([nodes[key]]);
|
|
||||||
nodes.splice(key, 1);
|
|
||||||
for (const level of levels) {
|
|
||||||
const a = [];
|
|
||||||
for (const l of level) {
|
|
||||||
for (const n of calls) {
|
|
||||||
if (n.target === l.id) {
|
|
||||||
const i = nodes.findIndex((d: Node) => d.id === n.source);
|
|
||||||
if (i > -1) {
|
|
||||||
a.push(nodes[i]);
|
|
||||||
nodes.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (n.source === l.id) {
|
|
||||||
const i = nodes.findIndex((d: Node) => d.id === n.target);
|
|
||||||
if (i > -1) {
|
|
||||||
a.push(nodes[i]);
|
|
||||||
nodes.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (a.length) {
|
|
||||||
levels.push(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nodes.length) {
|
|
||||||
const ids = nodes.map((d: Node) => d.id);
|
|
||||||
const links = calls.filter((item: Call) => ids.includes(item.source) || ids.includes(item.target));
|
|
||||||
const list = computeLevels(links, nodes, []);
|
|
||||||
levels = list.map((subArrayA, index) => subArrayA.concat(levels[index]));
|
|
||||||
}
|
|
||||||
return levels;
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
const levels = computeLevels(topologyStore.calls, topologyStore.nodes, []);
|
const levels = computeLevels(topologyStore.calls, topologyStore.nodes, []);
|
||||||
|
|
||||||
topologyLayout.value = layout(levels, topologyStore.calls, radius);
|
topologyLayout.value = layout(levels, topologyStore.calls, radius);
|
||||||
graphWidth.value = topologyLayout.value.layout.width;
|
graphWidth.value = topologyLayout.value.layout.width;
|
||||||
const drag: any = d3.drag().on("drag", (d: { x: number; y: number }) => {
|
const drag: any = d3.drag().on("drag", (d: { x: number; y: number }) => {
|
||||||
moveNode(d);
|
topologyLayout.value.calls = changeNode(d, currentNode.value, topologyLayout.value, radius);
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
d3.selectAll(".topo-node").call(drag);
|
d3.selectAll(".topo-node").call(drag);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveNode(d: { x: number; y: number }) {
|
|
||||||
if (!currentNode.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const node of topologyLayout.value.nodes) {
|
|
||||||
if (node.id === currentNode.value.id) {
|
|
||||||
node.x = d.x;
|
|
||||||
node.y = d.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const call of topologyLayout.value.calls) {
|
|
||||||
if (call.sourceObj.id === currentNode.value.id) {
|
|
||||||
call.sourceObj.x = d.x;
|
|
||||||
call.sourceObj.y = d.y;
|
|
||||||
}
|
|
||||||
if (call.targetObj.id === currentNode.value.id) {
|
|
||||||
call.targetObj.x = d.x;
|
|
||||||
call.targetObj.y = d.y;
|
|
||||||
}
|
|
||||||
if (call.targetObj.id === currentNode.value.id || call.sourceObj.id === currentNode.value.id) {
|
|
||||||
const pos: any = circleIntersection(
|
|
||||||
call.sourceObj.x,
|
|
||||||
call.sourceObj.y,
|
|
||||||
radius,
|
|
||||||
call.targetObj.x,
|
|
||||||
call.targetObj.y,
|
|
||||||
radius,
|
|
||||||
);
|
|
||||||
call.sourceX = pos[0].x;
|
|
||||||
call.sourceY = pos[0].y;
|
|
||||||
call.targetX = pos[1].x;
|
|
||||||
call.targetY = pos[1].y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
topologyLayout.value.calls = computeCallPos(topologyLayout.value.calls, radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
function startMoveNode(event: MouseEvent, d: Node) {
|
function startMoveNode(event: MouseEvent, d: Node) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
currentNode.value = d;
|
currentNode.value = d;
|
||||||
@ -363,28 +275,6 @@ limitations under the License. -->
|
|||||||
currentNode.value = null;
|
currentNode.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findMostFrequent(arr: Call[]) {
|
|
||||||
let count: any = {};
|
|
||||||
let maxCount = 0;
|
|
||||||
let maxItem = null;
|
|
||||||
|
|
||||||
for (let i = 0; i < arr.length; i++) {
|
|
||||||
let item = arr[i];
|
|
||||||
count[item.sourceObj.id] = (count[item.sourceObj.id] || 0) + 1;
|
|
||||||
if (count[item.sourceObj.id] > maxCount) {
|
|
||||||
maxCount = count[item.sourceObj.id];
|
|
||||||
maxItem = item.sourceObj;
|
|
||||||
}
|
|
||||||
count[item.targetObj.id] = (count[item.targetObj.id] || 0) + 1;
|
|
||||||
if (count[item.targetObj.id] > maxCount) {
|
|
||||||
maxCount = count[item.targetObj.id];
|
|
||||||
maxItem = item.targetObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return maxItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initLegendMetrics() {
|
async function initLegendMetrics() {
|
||||||
if (!topologyStore.nodes.length) {
|
if (!topologyStore.nodes.length) {
|
||||||
return;
|
return;
|
||||||
|
@ -56,15 +56,6 @@ limitations under the License. -->
|
|||||||
stroke="#97B0F8"
|
stroke="#97B0F8"
|
||||||
marker-end="url(#arrow)"
|
marker-end="url(#arrow)"
|
||||||
/>
|
/>
|
||||||
<circle
|
|
||||||
class="topo-line-anchor"
|
|
||||||
:cx="(l.sourceX + l.targetX) / 2"
|
|
||||||
:cy="(l.sourceY + l.targetY) / 2"
|
|
||||||
r="4"
|
|
||||||
fill="#97B0F8"
|
|
||||||
@mouseover="showLinkTip($event, l)"
|
|
||||||
@mouseout="hideTip"
|
|
||||||
/>
|
|
||||||
</g>
|
</g>
|
||||||
<g class="arrows">
|
<g class="arrows">
|
||||||
<defs v-for="(_, index) in topologyLayout.calls" :key="index">
|
<defs v-for="(_, index) in topologyLayout.calls" :key="index">
|
||||||
@ -106,7 +97,7 @@ limitations under the License. -->
|
|||||||
import { aggregation } from "@/hooks/useMetricsProcessor";
|
import { aggregation } from "@/hooks/useMetricsProcessor";
|
||||||
import icons from "@/assets/img/icons";
|
import icons from "@/assets/img/icons";
|
||||||
import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor";
|
import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor";
|
||||||
import { layout, circleIntersection, computeCallPos } from "./utils/layout";
|
import { layout, changeNode, computeLevels } from "./utils/layout";
|
||||||
import zoom from "../../components/utils/zoom";
|
import zoom from "../../components/utils/zoom";
|
||||||
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
|
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
|
|
||||||
@ -133,7 +124,7 @@ limitations under the License. -->
|
|||||||
const topologyLayout = ref<any>({});
|
const topologyLayout = ref<any>({});
|
||||||
const popover = ref<Nullable<any>>(null);
|
const popover = ref<Nullable<any>>(null);
|
||||||
const graphWidth = ref<number>(100);
|
const graphWidth = ref<number>(100);
|
||||||
const currentNode = ref<Nullable<Node>>();
|
const currentNode = ref<Nullable<Node>>(null);
|
||||||
const diff = computed(() => [(width.value - graphWidth.value) / 2, 0]);
|
const diff = computed(() => [(width.value - graphWidth.value) / 2, 0]);
|
||||||
const radius = 8;
|
const radius = 8;
|
||||||
|
|
||||||
@ -180,107 +171,19 @@ limitations under the License. -->
|
|||||||
popover.value = d3.select("#popover");
|
popover.value = d3.select("#popover");
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeLevels(calls: Call[], nodeList: Node[], levels: any[]) {
|
|
||||||
const node = findMostFrequent(calls);
|
|
||||||
const nodes = JSON.parse(JSON.stringify(nodeList)).sort((a: Node, b: Node) => {
|
|
||||||
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (a.name.toLowerCase() > b.name.toLowerCase()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
const index = nodes.findIndex((n: Node) => n.type === "USER");
|
|
||||||
let key = index;
|
|
||||||
if (index < 0) {
|
|
||||||
key = nodes.findIndex((n: Node) => n.id === node.id);
|
|
||||||
}
|
|
||||||
levels.push([nodes[key]]);
|
|
||||||
nodes.splice(key, 1);
|
|
||||||
for (const level of levels) {
|
|
||||||
const a = [];
|
|
||||||
for (const l of level) {
|
|
||||||
for (const n of calls) {
|
|
||||||
if (n.target === l.id) {
|
|
||||||
const i = nodes.findIndex((d: Node) => d.id === n.source);
|
|
||||||
if (i > -1) {
|
|
||||||
a.push(nodes[i]);
|
|
||||||
nodes.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (n.source === l.id) {
|
|
||||||
const i = nodes.findIndex((d: Node) => d.id === n.target);
|
|
||||||
if (i > -1) {
|
|
||||||
a.push(nodes[i]);
|
|
||||||
nodes.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (a.length) {
|
|
||||||
levels.push(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nodes.length) {
|
|
||||||
const ids = nodes.map((d: Node) => d.id);
|
|
||||||
const links = calls.filter((item: Call) => ids.includes(item.source) || ids.includes(item.target));
|
|
||||||
const list = computeLevels(links, nodes, []);
|
|
||||||
levels = list.map((subArrayA, index) => subArrayA.concat(levels[index]));
|
|
||||||
}
|
|
||||||
return levels;
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
const levels = computeLevels(topologyStore.calls, topologyStore.nodes, []);
|
const levels = computeLevels(topologyStore.calls, topologyStore.nodes, []);
|
||||||
|
|
||||||
topologyLayout.value = layout(levels, topologyStore.calls, radius);
|
topologyLayout.value = layout(levels, topologyStore.calls, radius);
|
||||||
graphWidth.value = topologyLayout.value.layout.width;
|
graphWidth.value = topologyLayout.value.layout.width;
|
||||||
const drag: any = d3.drag().on("drag", (d: { x: number; y: number }) => {
|
const drag: any = d3.drag().on("drag", (d: { x: number; y: number }) => {
|
||||||
moveNode(d);
|
topologyLayout.value.calls = changeNode(d, currentNode.value, topologyLayout.value, radius);
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
d3.selectAll(".topo-node").call(drag);
|
d3.selectAll(".topo-node").call(drag);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveNode(d: { x: number; y: number }) {
|
|
||||||
if (!currentNode.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const node of topologyLayout.value.nodes) {
|
|
||||||
if (node.id === currentNode.value.id) {
|
|
||||||
node.x = d.x;
|
|
||||||
node.y = d.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const call of topologyLayout.value.calls) {
|
|
||||||
if (call.sourceObj.id === currentNode.value.id) {
|
|
||||||
call.sourceObj.x = d.x;
|
|
||||||
call.sourceObj.y = d.y;
|
|
||||||
}
|
|
||||||
if (call.targetObj.id === currentNode.value.id) {
|
|
||||||
call.targetObj.x = d.x;
|
|
||||||
call.targetObj.y = d.y;
|
|
||||||
}
|
|
||||||
if (call.targetObj.id === currentNode.value.id || call.sourceObj.id === currentNode.value.id) {
|
|
||||||
const pos: any = circleIntersection(
|
|
||||||
call.sourceObj.x,
|
|
||||||
call.sourceObj.y,
|
|
||||||
radius,
|
|
||||||
call.targetObj.x,
|
|
||||||
call.targetObj.y,
|
|
||||||
radius,
|
|
||||||
);
|
|
||||||
call.sourceX = pos[0].x;
|
|
||||||
call.sourceY = pos[0].y;
|
|
||||||
call.targetX = pos[1].x;
|
|
||||||
call.targetY = pos[1].y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
topologyLayout.value.calls = computeCallPos(topologyLayout.value.calls, radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
function startMoveNode(event: MouseEvent, d: Node) {
|
function startMoveNode(event: MouseEvent, d: Node) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
currentNode.value = d;
|
currentNode.value = d;
|
||||||
@ -290,28 +193,6 @@ limitations under the License. -->
|
|||||||
currentNode.value = null;
|
currentNode.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findMostFrequent(arr: Call[]) {
|
|
||||||
let count: any = {};
|
|
||||||
let maxCount = 0;
|
|
||||||
let maxItem = null;
|
|
||||||
|
|
||||||
for (let i = 0; i < arr.length; i++) {
|
|
||||||
let item = arr[i];
|
|
||||||
count[item.sourceObj.id] = (count[item.sourceObj.id] || 0) + 1;
|
|
||||||
if (count[item.sourceObj.id] > maxCount) {
|
|
||||||
maxCount = count[item.sourceObj.id];
|
|
||||||
maxItem = item.sourceObj;
|
|
||||||
}
|
|
||||||
count[item.targetObj.id] = (count[item.targetObj.id] || 0) + 1;
|
|
||||||
if (count[item.targetObj.id] > maxCount) {
|
|
||||||
maxCount = count[item.targetObj.id];
|
|
||||||
maxItem = item.targetObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return maxItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initLegendMetrics() {
|
async function initLegendMetrics() {
|
||||||
if (!topologyStore.nodes.length) {
|
if (!topologyStore.nodes.length) {
|
||||||
return;
|
return;
|
||||||
@ -398,19 +279,11 @@ limitations under the License. -->
|
|||||||
.style("visibility", "visible")
|
.style("visibility", "visible")
|
||||||
.html(tipHtml);
|
.html(tipHtml);
|
||||||
}
|
}
|
||||||
function showLinkTip(event: MouseEvent, data: Call) {
|
|
||||||
const html = `<div><span class="grey">${t("detectPoint")}:</span>${data.detectPoints.join(" | ")}</div>`;
|
|
||||||
|
|
||||||
popover.value
|
|
||||||
.style("top", event.offsetY + "px")
|
|
||||||
.style("left", event.offsetX + "px")
|
|
||||||
.style("visibility", "visible")
|
|
||||||
.html(html);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideTip() {
|
function hideTip() {
|
||||||
popover.value.style("visibility", "hidden");
|
popover.value.style("visibility", "hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleNodeClick(event: MouseEvent, d: Node & { x: number; y: number }) {
|
function handleNodeClick(event: MouseEvent, d: Node & { x: number; y: number }) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
hideTip();
|
hideTip();
|
||||||
@ -425,12 +298,7 @@ limitations under the License. -->
|
|||||||
window.open(routeUrl.href, "_blank");
|
window.open(routeUrl.href, "_blank");
|
||||||
dashboardStore.setEntity(origin);
|
dashboardStore.setEntity(origin);
|
||||||
}
|
}
|
||||||
function handleGoAlerting() {
|
|
||||||
const path = `/alerting`;
|
|
||||||
const routeUrl = router.resolve({ path });
|
|
||||||
|
|
||||||
window.open(routeUrl.href, "_blank");
|
|
||||||
}
|
|
||||||
async function getTopology() {
|
async function getTopology() {
|
||||||
const ids = selectorStore.services.map((d: Service) => d.id);
|
const ids = selectorStore.services.map((d: Service) => d.id);
|
||||||
const serviceIds = dashboardStore.entity === EntityType[0].value ? [selectorStore.currentService.id] : ids;
|
const serviceIds = dashboardStore.entity === EntityType[0].value ? [selectorStore.currentService.id] : ids;
|
@ -120,3 +120,115 @@ export function circleIntersection(ax: number, ay: number, ar: number, bx: numbe
|
|||||||
{ x: gx, y: gy },
|
{ x: gx, y: gy },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
function findMostFrequent(arr: Call[]) {
|
||||||
|
const count: any = {};
|
||||||
|
let maxCount = 0;
|
||||||
|
let maxItem = null;
|
||||||
|
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
const item = arr[i];
|
||||||
|
count[item.sourceObj.id] = (count[item.sourceObj.id] || 0) + 1;
|
||||||
|
if (count[item.sourceObj.id] > maxCount) {
|
||||||
|
maxCount = count[item.sourceObj.id];
|
||||||
|
maxItem = item.sourceObj;
|
||||||
|
}
|
||||||
|
count[item.targetObj.id] = (count[item.targetObj.id] || 0) + 1;
|
||||||
|
if (count[item.targetObj.id] > maxCount) {
|
||||||
|
maxCount = count[item.targetObj.id];
|
||||||
|
maxItem = item.targetObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxItem;
|
||||||
|
}
|
||||||
|
export function computeLevels(calls: Call[], nodeList: Node[], levels: any[]) {
|
||||||
|
const node = findMostFrequent(calls);
|
||||||
|
const nodes = JSON.parse(JSON.stringify(nodeList)).sort((a: Node, b: Node) => {
|
||||||
|
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.name.toLowerCase() > b.name.toLowerCase()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
const index = nodes.findIndex((n: Node) => n.type === "USER");
|
||||||
|
let key = index;
|
||||||
|
if (index < 0) {
|
||||||
|
key = nodes.findIndex((n: Node) => n.id === node.id);
|
||||||
|
}
|
||||||
|
levels.push([nodes[key]]);
|
||||||
|
nodes.splice(key, 1);
|
||||||
|
for (const level of levels) {
|
||||||
|
const a = [];
|
||||||
|
for (const l of level) {
|
||||||
|
for (const n of calls) {
|
||||||
|
if (n.target === l.id) {
|
||||||
|
const i = nodes.findIndex((d: Node) => d.id === n.source);
|
||||||
|
if (i > -1) {
|
||||||
|
a.push(nodes[i]);
|
||||||
|
nodes.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n.source === l.id) {
|
||||||
|
const i = nodes.findIndex((d: Node) => d.id === n.target);
|
||||||
|
if (i > -1) {
|
||||||
|
a.push(nodes[i]);
|
||||||
|
nodes.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a.length) {
|
||||||
|
levels.push(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nodes.length) {
|
||||||
|
const ids = nodes.map((d: Node) => d.id);
|
||||||
|
const links = calls.filter((item: Call) => ids.includes(item.source) || ids.includes(item.target));
|
||||||
|
const list = computeLevels(links, nodes, []);
|
||||||
|
levels = list.map((subArrayA, index) => subArrayA.concat(levels[index]));
|
||||||
|
}
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
export function changeNode(
|
||||||
|
d: { x: number; y: number },
|
||||||
|
currentNode: Nullable<Node>,
|
||||||
|
topologyLayout: any,
|
||||||
|
radius: number,
|
||||||
|
) {
|
||||||
|
if (!currentNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const node of topologyLayout.nodes) {
|
||||||
|
if (node.id === currentNode.id) {
|
||||||
|
node.x = d.x;
|
||||||
|
node.y = d.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const call of topologyLayout.calls) {
|
||||||
|
if (call.sourceObj.id === currentNode.id) {
|
||||||
|
call.sourceObj.x = d.x;
|
||||||
|
call.sourceObj.y = d.y;
|
||||||
|
}
|
||||||
|
if (call.targetObj.id === currentNode.id) {
|
||||||
|
call.targetObj.x = d.x;
|
||||||
|
call.targetObj.y = d.y;
|
||||||
|
}
|
||||||
|
if (call.targetObj.id === currentNode.id || call.sourceObj.id === currentNode.id) {
|
||||||
|
const pos: any = circleIntersection(
|
||||||
|
call.sourceObj.x,
|
||||||
|
call.sourceObj.y,
|
||||||
|
radius,
|
||||||
|
call.targetObj.x,
|
||||||
|
call.targetObj.y,
|
||||||
|
radius,
|
||||||
|
);
|
||||||
|
call.sourceX = pos[0].x;
|
||||||
|
call.sourceY = pos[0].y;
|
||||||
|
call.targetX = pos[1].x;
|
||||||
|
call.targetY = pos[1].y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return computeCallPos(topologyLayout.value.calls, radius);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user