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

chenyulin0719 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-web.git


The following commit(s) were added to refs/heads/master by this push:
     new a651479  [YUNIKORN-2347] Navigate to the center of the queue SVG (#186)
a651479 is described below

commit a6514793169ce9b7ce5d963f940e919a9bcc933d
Author: DouPache <[email protected]>
AuthorDate: Sat Apr 20 19:14:37 2024 +0800

    [YUNIKORN-2347] Navigate to the center of the queue SVG (#186)
    
    Closes: #186
    
    Signed-off-by: Yu-Lin Chen <[email protected]>
---
 .../components/queue-v2/queues-v2.component.html   |  6 ++
 .../components/queue-v2/queues-v2.component.scss   | 56 +++++++++++++---
 src/app/components/queue-v2/queues-v2.component.ts | 74 ++++++++++++++++++----
 3 files changed, 114 insertions(+), 22 deletions(-)

diff --git a/src/app/components/queue-v2/queues-v2.component.html 
b/src/app/components/queue-v2/queues-v2.component.html
index a3c137e..c3e5153 100644
--- a/src/app/components/queue-v2/queues-v2.component.html
+++ b/src/app/components/queue-v2/queues-v2.component.html
@@ -21,6 +21,12 @@
       <div class="header">
         <div class="title-group">
           <div>Partition</div>
+          <button id="fitButton" class="fit-to-screen-button">
+            <svg xmlns="http://www.w3.org/2000/svg"; width="24" height="24" 
viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.5" 
stroke-linecap="round" stroke-linejoin="round" class="w-6 h-6">
+              <path d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 
12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 
1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 
1.125-1.125V9.75M8.25 21h8.25" />          
+            </svg>
+            <span id="tooltip" class="tooltip" role="tooltip">fit to 
screen</span>
+          </button>
         </div>
       </div>
       <div class="body">
diff --git a/src/app/components/queue-v2/queues-v2.component.scss 
b/src/app/components/queue-v2/queues-v2.component.scss
index f9a55f1..fd3fd4a 100644
--- a/src/app/components/queue-v2/queues-v2.component.scss
+++ b/src/app/components/queue-v2/queues-v2.component.scss
@@ -23,28 +23,64 @@
     background-color: white;
     padding: 20px; /* Adjust padding to your preference */
     box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 
0, 0.05);
-    overflow: auto; /* Add scroll for overflow content */
+    overflow: show; /* Add scroll for overflow content */
   }
   
   .header .title-group {
     display: flex;
     align-items: center;
-    justify-content: center;
+    justify-content: space-between;
     padding-bottom: 1rem;
   }
-  
-  .title-group .icon {
-    height: 2rem;
-    width: 2rem;
-    margin-right: 10px;
-  }
-  
+   
   .title-group div {
+    flex-grow: 1; 
+    text-align: center;
     font-size: 1.25rem; 
     font-weight: 600; 
-    color: #010407; 
+    color: #010407;
   } 
   
+  .fit-to-screen-button {
+    position: relative;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    padding: 6px 6px;
+    background-color: #e5ecf6;
+    border: 1px solid #132030;
+    border-radius: 5px;
+    cursor: pointer;
+    overflow: show;
+  }
+
+  .tooltip {
+      width: 100px;
+      position: absolute;
+      bottom: 90%;
+      left: 50%;
+      transform: translateX(-50%);
+      background-color: rgb(225, 228, 241);
+      color: rgb(6, 7, 6);
+      text-align: center;
+      padding: 5px 5px;
+      border-radius: 6px;
+      visibility: hidden;
+      opacity: 1;
+      transition: opacity 0.3s, visibility 0.3s;
+  }
+
+  .fit-to-screen-button:hover .tooltip {
+      margin-bottom: 10px;
+      visibility: visible;
+      opacity: 1;
+  }
+
+
+  .fit-to-screen-button:hover {
+      background-color: #8090a5;
+  }
+
   .visualize-area {
     display: flex;
     flex-direction: column;
diff --git a/src/app/components/queue-v2/queues-v2.component.ts 
b/src/app/components/queue-v2/queues-v2.component.ts
index 823a8db..58f8da2 100644
--- a/src/app/components/queue-v2/queues-v2.component.ts
+++ b/src/app/components/queue-v2/queues-v2.component.ts
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit} from '@angular/core';
 import { Router } from '@angular/router';
 import { NgxSpinnerService } from 'ngx-spinner';
 import { QueueInfo } from '@app/models/queue-info.model';
@@ -69,23 +69,77 @@ export class QueueV2Component implements OnInit {
         if (data && data.rootQueue) {
           this.rootQueue = data.rootQueue;
           queueVisualization(this.rootQueue as QueueInfo)
+          setTimeout(() => this.adjustToScreen(),1000) // since the 
ngAfterViewInit hook is not working, we used setTimeout instead
         }
       });
   }
+
+  adjustToScreen() {
+    const fitButton = document.getElementById('fitButton');
+    fitButton?.click(); 
+  }
 }
 
 function queueVisualization(rawData : QueueInfo){
+  let numberOfNode = 0;
+  const duration = 750;
+
   const svg = select('.visualize-area').append('svg')
                .attr('width', '100%')
                .attr('height', '100%')
-              
-    const svgWidth = 1150;
-    const svgHeight = 600;
+                  
+    function fitGraphScale(){
+      const baseSvgElem = svg.node() as SVGGElement;
+      const bounds = baseSvgElem.getBBox();
+      const parent = baseSvgElem.parentElement as HTMLElement;
+      const fullWidth = parent.clientWidth;
+      const fullHeight = parent.clientHeight;
+      
+      const xfactor: number = fullWidth / bounds.width;
+      const yfactor: number = fullHeight / bounds.height;
+      let scaleFactor: number = Math.min(xfactor, yfactor);
+
+       // Add some padding so that the graph is not touching the edges
+       const paddingPercent = 0.9;
+       scaleFactor = scaleFactor * paddingPercent;
+       return scaleFactor
+    }
+
+    function centerGraph() {
+        const bbox = (svgGroup.node() as SVGGElement).getBBox();
+        const cx = bbox.x + bbox.width / 2;
+        const cy = bbox.y + bbox.height / 2;
+        return {cx, cy};
+    }
 
-    // Center the group
+    function adjustVisulizeArea(duration : number = 0){
+      const scaleFactor = fitGraphScale();
+      const {cx, cy} = centerGraph();
+      // make the total duration to be 1 second
+      svg.transition().duration(duration/1.5).call(zoom.translateTo, cx, cy)
+      .on("end", function() {
+        svg.transition().duration(duration/1.5).call(zoom.scaleBy, scaleFactor)
+      })
+    } 
+
+    // Append a svg group which holds all nodes and which is for the d3 zoom
     const svgGroup = svg.append("g")
-      .attr("transform", `translate(${svgWidth / 3}, ${svgHeight / 10})`); 
-  
+
+    const fitButton = select(".fit-to-screen-button")
+    .on("click", function() {
+      adjustVisulizeArea(duration)
+    })
+    .on('mouseenter', function() {
+      select(this).select('.tooltip')
+            .style('visibility', 'visible')
+            .style('opacity', 1);
+    })
+    .on('mouseleave', function() {
+      select(this).select('.tooltip')
+            .style('visibility', 'hidden')
+            .style('opacity', 0);
+    });
+    
     const treelayout = d3flextree
       .flextree<QueueInfo>({})
       .nodeSize((d) => {
@@ -98,15 +152,11 @@ function queueVisualization(rawData : QueueInfo){
     .zoom<SVGSVGElement, unknown>()
     .scaleExtent([0.1, 5]) 
     .on("zoom", (event) => {
-      const initialTransform = d3zoom.zoomIdentity.translate(svgWidth / 3, 
svgHeight / 10);
-      svgGroup.attr("transform", event.transform.toString() + 
initialTransform.toString());
+      svgGroup.attr("transform", event.transform)
     });
     svg.call(zoom);
 
-    let numberOfNode = 0;
-    const duration = 750;
     const root = d3hierarchy.hierarchy(rawData);
-
     update(root);
 
     function update(source: any){


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to