You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by qi...@apache.org on 2023/02/15 05:32:38 UTC

[skywalking-booster-ui] branch main updated: refactor: optimize the attached events visualization in the trace widget (#234)

This is an automated email from the ASF dual-hosted git repository.

qiuxiafan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-booster-ui.git


The following commit(s) were added to refs/heads/main by this push:
     new a1066f0  refactor: optimize the attached events visualization in the trace widget (#234)
a1066f0 is described below

commit a1066f09e40083efa72b5081d9ac63efdcaa0a22
Author: Fine0830 <fa...@gmail.com>
AuthorDate: Wed Feb 15 13:32:32 2023 +0800

    refactor: optimize the attached events visualization in the trace widget (#234)
---
 src/layout/components/SideBar.vue                  | 15 +++-
 .../trace/components/D3Graph/SpanDetail.vue        | 88 ++++++++++------------
 .../dashboard/related/trace/utils/d3-trace-list.ts | 17 ++++-
 3 files changed, 69 insertions(+), 51 deletions(-)

diff --git a/src/layout/components/SideBar.vue b/src/layout/components/SideBar.vue
index 77ebdce..f630503 100644
--- a/src/layout/components/SideBar.vue
+++ b/src/layout/components/SideBar.vue
@@ -13,7 +13,7 @@ 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 class="side-bar" v-if="showMenu" @click="isCollapse = false" @mouseleave="isCollapse = true">
+  <div class="side-bar" v-if="showMenu" @click="isCollapse = false" @mouseleave="closeMenu">
     <div :class="isCollapse ? 'logo-icon-collapse' : 'logo-icon'">
       <Icon :size="isCollapse ? 'xl' : 'logo'" :iconName="isCollapse ? 'logo' : 'logo-sw'" />
     </div>
@@ -81,6 +81,7 @@ limitations under the License. -->
   const route = useRoute();
   const isCollapse = ref(true);
   const showMenu = ref(true);
+  const open = ref<boolean>(false);
 
   if (/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
     appStore.setIsMobile(true);
@@ -97,7 +98,17 @@ limitations under the License. -->
     return menus.filter((d) => d.meta && !d.meta.notShow);
   };
   function setCollapse() {
-    isCollapse.value = false;
+    open.value = true;
+    setTimeout(() => {
+      if (open.value) {
+        isCollapse.value = false;
+      }
+      open.value = false;
+    }, 1000);
+  }
+  function closeMenu() {
+    isCollapse.value = true;
+    open.value = false;
   }
 </script>
 
diff --git a/src/views/dashboard/related/trace/components/D3Graph/SpanDetail.vue b/src/views/dashboard/related/trace/components/D3Graph/SpanDetail.vue
index 0f7ae37..ee813dd 100644
--- a/src/views/dashboard/related/trace/components/D3Graph/SpanDetail.vue
+++ b/src/views/dashboard/related/trace/components/D3Graph/SpanDetail.vue
@@ -74,7 +74,7 @@ limitations under the License. -->
     <h5 class="mb-10" v-if="currentSpan.attachedEvents && currentSpan.attachedEvents.length"> {{ t("events") }}. </h5>
     <div
       class="attach-events"
-      ref="timeline"
+      ref="eventGraph"
       v-if="currentSpan.attachedEvents && currentSpan.attachedEvents.length"
     ></div>
     <el-button class="popup-btn" type="primary" @click="getTaceLogs">
@@ -131,8 +131,7 @@ limitations under the License. -->
   import { useI18n } from "vue-i18n";
   import type { PropType } from "vue";
   import dayjs from "dayjs";
-  import { DataSet, Timeline } from "vis-timeline/standalone";
-  import "vis-timeline/styles/vis-timeline-graph2d.css";
+  import ListGraph from "../../utils/d3-trace-list";
   import copy from "@/utils/copy";
   import { ElMessage } from "element-plus";
   import { dateFormat } from "@/utils/dateFormat";
@@ -146,8 +145,6 @@ limitations under the License. -->
   });
   const { t } = useI18n();
   const traceStore = useTraceStore();
-  const timeline = ref<Nullable<HTMLDivElement>>(null);
-  const visGraph = ref<Nullable<any>>(null);
   const pageNum = ref<number>(1);
   const showRelatedLogs = ref<boolean>(false);
   const showEventDetail = ref<boolean>(false);
@@ -156,6 +153,8 @@ limitations under the License. -->
   const total = computed(() =>
     traceStore.traceList.length === pageSize ? pageSize * pageNum.value + 1 : pageSize * pageNum.value,
   );
+  const tree = ref<any>(null);
+  const eventGraph = ref<Nullable<HTMLDivElement>>(null);
   const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") => dayjs(date).format(pattern);
 
   onMounted(() => {
@@ -180,52 +179,46 @@ limitations under the License. -->
     }
   }
   function visTimeline() {
-    if (!timeline.value) {
+    if (!eventGraph.value) {
       return;
     }
-    if (visGraph.value) {
-      visGraph.value.destroy();
-    }
-    const h = timeline.value.getBoundingClientRect().height;
     const attachedEvents = props.currentSpan.attachedEvents || [];
-    const events: any[] = attachedEvents.map((d: SpanAttachedEvent, index: number) => {
-      let startTimeNanos = String(d.startTime.nanos).slice(-6).padStart(6, "0");
-      let endTimeNanos = String(d.endTime.nanos).slice(-6).padStart(6, "0");
-      endTimeNanos = toString(endTimeNanos);
-      startTimeNanos = toString(startTimeNanos);
-      return {
-        id: index + 1,
-        content: d.event,
-        start: new Date(Number(d.startTime.seconds * 1000 + d.startTime.nanos / 1000000)),
-        end: new Date(Number(d.endTime.seconds * 1000 + d.endTime.nanos / 1000000)),
-        ...d,
-        startTime: d.startTime.seconds * 1000 + d.startTime.nanos / 1000000,
-        endTime: d.endTime.seconds * 1000 + d.endTime.nanos / 1000000,
-        className: "Normal",
-        startTimeNanos,
-        endTimeNanos,
-      };
-    });
+    const events: any[] = attachedEvents
+      .map((d: SpanAttachedEvent) => {
+        let startTimeNanos = String(d.startTime.nanos).slice(-6).padStart(6, "0");
+        let endTimeNanos = String(d.endTime.nanos).slice(-6).padStart(6, "0");
+        endTimeNanos = toString(endTimeNanos);
+        startTimeNanos = toString(startTimeNanos);
+        const startTime = d.startTime.seconds * 1000 + d.startTime.nanos / 1000000;
+        const endTime = d.endTime.seconds * 1000 + d.endTime.nanos / 1000000;
+        return {
+          label: d.event,
+          ...d,
+          startTime,
+          endTime,
+          startTimeNanos,
+          endTimeNanos,
+        };
+      })
+      .sort((a: { startTime: number; endTime: number }, b: { startTime: number; endTime: number }) => {
+        return a.startTime - b.startTime;
+      });
 
-    const items = new DataSet(events);
-    const options: any = {
-      height: h,
-      width: "100%",
-      locale: "en",
-      groupHeightMode: "fitItems",
-      zoomMin: 80,
-    };
+    tree.value = new ListGraph(eventGraph.value, selectEvent);
+    tree.value.init(
+      {
+        children: events,
+        label: "",
+      },
+      events,
+      0,
+    );
+    tree.value.draw();
+  }
 
-    visGraph.value = new Timeline(timeline.value, items, options);
-    visGraph.value.on("select", (data: { items: number[] }) => {
-      const index = data.items[0];
-      currentEvent.value = events[index - 1 || 0] || {};
-      if (data.items.length) {
-        showEventDetail.value = true;
-        return;
-      }
-      showEventDetail.value = false;
-    });
+  function selectEvent(i: any) {
+    currentEvent.value = i.data;
+    showEventDetail.value = true;
   }
   function toString(str: string) {
     return str.replace(/\d(?=(\d{3})+$)/g, "$&,");
@@ -247,7 +240,8 @@ limitations under the License. -->
   .attach-events {
     width: 100%;
     margin: 0 5px 5px 0;
-    height: 200px;
+    height: 400px;
+    overflow: auto;
   }
 
   .popup-btn {
diff --git a/src/views/dashboard/related/trace/utils/d3-trace-list.ts b/src/views/dashboard/related/trace/utils/d3-trace-list.ts
index 7bb39a6..8c14382 100644
--- a/src/views/dashboard/related/trace/utils/d3-trace-list.ts
+++ b/src/views/dashboard/related/trace/utils/d3-trace-list.ts
@@ -18,6 +18,7 @@
 import * as d3 from "d3";
 import d3tip from "d3-tip";
 import type { Trace } from "@/types/trace";
+import dayjs from "dayjs";
 
 export default class ListGraph {
   private barHeight = 48;
@@ -91,7 +92,6 @@ export default class ListGraph {
     this.svg
       .append("g")
       .attr("class", "trace-xaxis")
-
       .attr("transform", `translate(${this.width * 0.618 - 20},${30})`)
       .call(this.xAxis);
     this.sequentialScale = d3
@@ -164,6 +164,7 @@ export default class ListGraph {
       .attr("x", 35)
       .attr("y", -6)
       .attr("fill", "#333")
+      .style("font-size", "12px")
       .html((d: any) => {
         if (d.data.label === "TRACE_ROOT") {
           return "";
@@ -214,7 +215,16 @@ export default class ListGraph {
       .attr("y", 12)
       .attr("fill", "#ccc")
       .style("font-size", "11px")
-      .text((d: any) => `${d.data.layer || ""} ${d.data.component ? "- " + d.data.component : d.data.component || ""}`);
+      .text(
+        (d: any) =>
+          `${d.data.layer || ""} ${
+            d.data.component
+              ? "- " + d.data.component
+              : d.data.event
+              ? this.visDate(d.data.startTime) + ":" + d.data.startTimeNanos
+              : ""
+          }`,
+      );
     nodeEnter
       .append("rect")
       .attr("rx", 2)
@@ -305,6 +315,9 @@ export default class ListGraph {
       callback();
     }
   }
+  visDate(date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") {
+    return dayjs(date).format(pattern);
+  }
   resize() {
     if (!this.el) {
       return;