vis stacks

This commit is contained in:
Qiuxia Fan 2022-04-22 11:00:00 +08:00
parent 68122c0a28
commit cf46164337
7 changed files with 2654 additions and 24 deletions

31
package-lock.json generated
View File

@ -10,6 +10,7 @@
"dependencies": {
"axios": "^0.24.0",
"d3": "^7.3.0",
"d3-flame-graph": "^4.1.3",
"d3-tip": "^0.9.1",
"echarts": "^5.2.2",
"element-plus": "^2.0.2",
@ -9340,6 +9341,21 @@
"node": ">=12"
}
},
"node_modules/d3-flame-graph": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/d3-flame-graph/-/d3-flame-graph-4.1.3.tgz",
"integrity": "sha512-NijuhJZhaTMwobVgwGQ67x9PovqMMHXBbs0FMHEGJvsWZGuL4M7OsB03v8mHdyVyHhnQYGsYnb5w021e9+R+RQ==",
"dependencies": {
"d3-array": "^3.1.1",
"d3-dispatch": "^3.0.1",
"d3-ease": "^3.0.1",
"d3-format": "^3.0.1",
"d3-hierarchy": "^3.0.1",
"d3-scale": "^4.0.2",
"d3-selection": "^3.0.0",
"d3-transition": "^3.0.1"
}
},
"node_modules/d3-force": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
@ -36407,6 +36423,21 @@
"d3-dsv": "1 - 3"
}
},
"d3-flame-graph": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/d3-flame-graph/-/d3-flame-graph-4.1.3.tgz",
"integrity": "sha512-NijuhJZhaTMwobVgwGQ67x9PovqMMHXBbs0FMHEGJvsWZGuL4M7OsB03v8mHdyVyHhnQYGsYnb5w021e9+R+RQ==",
"requires": {
"d3-array": "^3.1.1",
"d3-dispatch": "^3.0.1",
"d3-ease": "^3.0.1",
"d3-format": "^3.0.1",
"d3-hierarchy": "^3.0.1",
"d3-scale": "^4.0.2",
"d3-selection": "^3.0.0",
"d3-transition": "^3.0.1"
}
},
"d3-force": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",

View File

@ -12,6 +12,7 @@
"dependencies": {
"axios": "^0.24.0",
"d3": "^7.3.0",
"d3-flame-graph": "^4.1.3",
"d3-tip": "^0.9.1",
"echarts": "^5.2.2",
"element-plus": "^2.0.2",

11
src/types/ebpf.d.ts vendored
View File

@ -56,3 +56,14 @@ export type Process = {
attributes: { name: string; value: string };
labels: string[];
};
export type StackElement = {
id: string;
originId: string;
name: string;
parentId: string;
symbol: string;
dumpCount: number;
stackType: string;
value: number;
children?: StackElement[];
};

View File

@ -82,13 +82,6 @@ const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
function changeLabels(opt: any[]) {
const arr = opt.map((d) => d.value);
// if (arr.includes("0")) {
// selectedLabels.value = labels.value.map((d: Option) => d.value);
// return;
// }
// selectedLabels.value = Array.from(new Set(arr));
selectedLabels.value = arr;
}

View File

@ -13,31 +13,95 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div>tree</div>
<div id="graph-stack" ref="graph"></div>
</template>
<script lang="ts" setup>
import { watch } from "vue";
import { ref, watch } from "vue";
import * as d3 from "d3";
import { flamegraph } from "d3-flame-graph";
import { useEbpfStore } from "@/store/modules/ebpf";
import { StackElement } from "@/types/ebpf";
import { json } from "./json";
import "d3-flame-graph/dist/d3-flamegraph.css";
/*global Nullable*/
const ebpfStore = useEbpfStore();
const stackTree = ref<Nullable<StackElement>>(null);
const graph = ref<Nullable<HTMLDivElement>>(null);
const flameChart = ref<any>(null);
function sortArr(arr: any[]) {
function drawGraph() {
if (flameChart.value) {
flameChart.value.destroy();
}
if (!ebpfStore.analyzeTrees.length) {
return (stackTree.value = null);
}
stackTree.value = processTree(ebpfStore.analyzeTrees);
const w = (graph.value && graph.value.getBoundingClientRect().width) || 10;
flameChart.value = flamegraph()
.width(w - 10)
.cellHeight(18)
.transitionDuration(750)
.minFrameSize(5)
.transitionEase(d3.easeCubic as any)
.sort(true)
.title("")
.onClick(onClick)
.selfValue(false)
.setColorMapper((d, originalColor) =>
d.highlight ? "#6aff8f" : originalColor
);
// stackTree.value = (json as any);
console.log(stackTree.value);
d3.select("#graph-stack")
.datum(stackTree.value)
.call(flameChart.value)
.call(invokeFind);
}
function onClick(d: any) {
console.info(`Clicked on ${d.data.name}, id: "${d.data.value}"`);
}
function resetZoom() {
if (!flameChart.value) {
return;
}
flameChart.value.resetZoom();
}
function invokeFind() {
const searchId = parseInt(location.hash.substring(1), 10);
if (searchId) {
find(searchId);
}
}
function find(id: number) {
var elem = flameChart.value.findById(id);
if (elem) {
flameChart.value.zoomTo(elem);
}
}
function processTree(arr: StackElement[]) {
const copyArr = JSON.parse(JSON.stringify(arr));
const obj: any = {};
const res = [];
let res = null;
for (const item of copyArr) {
obj[item.id] = item;
item.originId = item.id;
item.value = item.dumpCount;
item.name = item.symbol;
delete item.id;
obj[item.originId] = item;
}
for (const item of copyArr) {
if (item.parentId === "0") {
item.name = item.symbol;
item.value = item.dumpCount;
res.push(item);
res = item;
}
for (const key in obj) {
if (item.id === obj[key].parentId) {
obj[key].name = obj[key].symbol;
obj[key].value = obj[key].dumpCount;
if (item.originId === obj[key].parentId) {
if (item.children) {
item.children.push(obj[key]);
} else {
@ -46,13 +110,19 @@ function sortArr(arr: any[]) {
}
}
}
console.log(res);
return res;
}
watch(
() => ebpfStore.analyzeTrees,
() => {
sortArr(ebpfStore.analyzeTrees);
drawGraph();
}
);
</script>
<style>
#graph-stack {
width: 100%;
height: 350px;
cursor: pointer;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -88,7 +88,7 @@ limitations under the License. -->
</div>
<div>
<el-button
class="grey"
class="grey small"
:class="{ ghost: displayMode !== 'List' }"
@click="displayMode = 'List'"
>
@ -96,7 +96,7 @@ limitations under the License. -->
{{ t("list") }}
</el-button>
<el-button
class="grey"
class="grey small"
:class="{ ghost: displayMode !== 'Tree' }"
@click="displayMode = 'Tree'"
>
@ -104,7 +104,7 @@ limitations under the License. -->
{{ t("tree") }}
</el-button>
<el-button
class="grey"
class="grey small"
:class="{ ghost: displayMode !== 'Table' }"
@click="displayMode = 'Table'"
>
@ -112,7 +112,7 @@ limitations under the License. -->
{{ t("table") }}
</el-button>
<el-button
class="grey"
class="grey small"
:class="{ ghost: displayMode !== 'Statistics' }"
@click="displayMode = 'Statistics'"
>