You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by kb...@apache.org on 2019/06/10 09:45:47 UTC

[atlas] branch branch-0.8 updated: ATLAS-3259 : UI: Lineage improvements for branch-0.8

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

kbhatt pushed a commit to branch branch-0.8
in repository https://gitbox.apache.org/repos/asf/atlas.git


The following commit(s) were added to refs/heads/branch-0.8 by this push:
     new c3f767e  ATLAS-3259 : UI: Lineage improvements for branch-0.8
c3f767e is described below

commit c3f767e2d33757515c39fedb48c3aee1cd229240
Author: kevalbhatt <kb...@apache.org>
AuthorDate: Wed Jun 5 14:27:45 2019 +0530

    ATLAS-3259 : UI: Lineage improvements for branch-0.8
---
 dashboardv2/public/css/scss/graph.scss             | 318 +++----
 dashboardv2/public/css/scss/override.scss          |   2 +-
 .../entity-icon/disabled/falcon_feed_creation.png  | Bin 0 -> 6830 bytes
 .../disabled/falcon_feed_replication.png           | Bin 0 -> 6830 bytes
 .../img/entity-icon/disabled/falcon_process.png    | Bin 0 -> 6830 bytes
 .../disabled/impala_column_lineage_disabled.png    | Bin 0 -> 5630 bytes
 .../disabled/impala_process_disabled.png           | Bin 0 -> 6214 bytes
 .../img/entity-icon/falcon_feed_creation.png       | Bin 0 -> 9620 bytes
 .../img/entity-icon/falcon_feed_replication.png    | Bin 0 -> 9620 bytes
 .../public/img/entity-icon/falcon_process.png      | Bin 0 -> 9620 bytes
 .../img/entity-icon/impala_column_lineage.png      | Bin 0 -> 7417 bytes
 .../public/img/entity-icon/impala_process.png      | Bin 0 -> 8176 bytes
 dashboardv2/public/img/icon-gear-active.png        | Bin 18088 -> 0 bytes
 dashboardv2/public/img/icon-gear-delete.png        | Bin 17677 -> 0 bytes
 dashboardv2/public/img/icon-gear.png               | Bin 8302 -> 0 bytes
 dashboardv2/public/img/icon-table-active.png       | Bin 14468 -> 0 bytes
 dashboardv2/public/img/icon-table-delete.png       | Bin 14117 -> 0 bytes
 dashboardv2/public/img/icon-table.png              | Bin 6417 -> 0 bytes
 dashboardv2/public/js/main.js                      |   3 +-
 dashboardv2/public/js/router/Router.js             |   1 +
 .../js/templates/graph/LineageLayoutView_tmpl.html | 101 ++-
 dashboardv2/public/js/utils/Helper.js              | 135 +++
 dashboardv2/public/js/utils/Overrides.js           |  75 --
 dashboardv2/public/js/utils/Utils.js               |   9 -
 .../js/views/detail_page/DetailPageLayoutView.js   |   4 +-
 .../public/js/views/graph/LineageLayoutView.js     | 975 ++++++++++++++-------
 dashboardv2/public/js/views/graph/LineageUtils.js  | 304 +++++++
 27 files changed, 1326 insertions(+), 601 deletions(-)

diff --git a/dashboardv2/public/css/scss/graph.scss b/dashboardv2/public/css/scss/graph.scss
index 3646261..1328304 100644
--- a/dashboardv2/public/css/scss/graph.scss
+++ b/dashboardv2/public/css/scss/graph.scss
@@ -34,10 +34,18 @@
         font-family: $font_1;
     }
 
+    transition: opacity 0.3s linear;
+
     rect {
         stroke: $color_mountain_mist_approx;
         fill: $white;
         stroke-width: 1.5px;
+
+        &.serach-rect {
+            stroke: $color_keppel_approx;
+            fill: transparent;
+            stroke-width: 2.5px
+        }
     }
 
     .label {
@@ -50,6 +58,11 @@
         transition: all 0.3s;
         stroke-width: 1.5px;
 
+        &.node-detail-highlight {
+            stroke: $color_havelock_blue_approx;
+            stroke-width: 2px;
+        }
+
         &.nodeImage {
             &.green:hover {
                 stroke: #ffb203;
@@ -90,6 +103,12 @@
     }
 }
 
+.invisible {
+    .node circle {
+        transition: all 0s;
+    }
+}
+
 .edgePath {
     .path {
         cursor: pointer;
@@ -189,80 +208,6 @@ g.type-TK>rect {
     height: 100%;
     width: 100%;
     overflow: hidden;
-
-    .lineage-edge-details {
-        position: absolute;
-        left: 0;
-        overflow: auto;
-        top: 0px;
-        max-height: 100%;
-        box-shadow: 4px 13px 14px -12px;
-        background: #e7e7e7;
-        transform: scaleX(0);
-        width: 200px;
-        transition: transform 0.3s ease-in;
-
-        &.open {
-            transform: scaleX(1);
-        }
-
-        .title {
-            background: black;
-            color: white;
-            padding: 10px;
-            padding-left: 17px;
-            margin-top: 0;
-            font-size: 14px;
-
-            .navigation-font {
-                font-family: sans-serif;
-                padding: 0px 5px;
-                color: #fb4200;
-            }
-        }
-
-        .close-details {
-            position: absolute;
-            top: 0;
-            color: white;
-            left: 0;
-            height: 21px;
-            width: 21px;
-            cursor: pointer;
-            font-size: 16px;
-        }
-
-        .propagation-list {
-            overflow: auto;
-            list-style-type: none;
-            list-style-position: outside;
-            padding-left: 30px;
-        }
-
-        .overlay {
-            position: absolute;
-            left: 0;
-            top: 0;
-            right: 0;
-            bottom: 0;
-            background: #d2d2d2b8;
-            z-index: 99;
-        }
-
-        ul>li {
-            word-wrap: break-word;
-            margin-bottom: 5px;
-            text-align: left;
-        }
-    }
-}
-
-.lineage-filter-box {
-    background-color: #e6e6e6;
-    padding: 4px;
-    border-radius: 5px;
-    width: 100%;
-    box-shadow: 1px 3px 3px 2px #bfbfbf;
 }
 
 .graph-button-group {
@@ -273,115 +218,40 @@ g.type-TK>rect {
     .zoom-button-group {}
 }
 
-.lineage-fltr-panel,
-.lineage-search-panel {
+.box-panel {
     position: absolute;
+    top: 37px;
     border: 1px solid #ccc;
     width: 250px;
     max-height: 99%;
     overflow: auto;
     transition: all 0.3s ease;
     right: -273px;
-    box-shadow: 7px 1px 28px -3px;
-    background-color: #f5f5f5;
+    background-color: $white;
     z-index: 999;
+    box-shadow: 1px 19px 22px -17px;
+    border-radius: 10px;
+    max-height: 88%;
 
-    .header {
-        background: black;
-        color: white;
-        text-align: center;
-        margin-bottom: 15px;
-        position: absolute;
-        width: 100%;
+    &.slide-from-left {
+        left: -273px;
+        right: 0px;
 
-        >h4 {
-            padding: 0px 36px 0px 10px;
-            word-break: break-all;
-        }
-
-        .fltr-togler,
-        .search-togler {
-            position: absolute;
-            right: 0px;
-            top: 0px;
+        &.size-lg {
+            left: -373px;
         }
     }
 
-    .body {
-        padding: 10px;
-        margin-top: 39px;
-        width: 100%;
-        position: relative;
-        height: 150px;
-        overflow: auto;
+    &.size-lg {
+        width: 350px;
     }
-}
 
-.lineage-details.node-details.open {
-    overflow: hidden !important;
-    min-height: 300px;
+    &.show-box-panel {
+        right: 0px !important;
 
-    & span[data-id='close'] {
-        margin: 7px;
-        position: absolute;
-        right: 0;
-        z-index: 99;
-    }
-
-    & div[data-id="entityList"] {
-        position: relative;
-        overflow: auto;
-        max-height: 250px;
-        top: 40px;
-    }
-
-    & h4.title {
-        position: fixed;
-        width: 100%;
-    }
-
-    & table {
-        & tbody td {
-            word-wrap: break-word
+        &.slide-from-left {
+            left: 0;
         }
-
-        table-layout: fixed;
-    }
-}
-
-.lineage-details {
-    position: absolute;
-    left: 0;
-    overflow: auto;
-    top: 0px;
-    max-height: 100%;
-    box-shadow: 4px 13px 14px -12px;
-    background: #e7e7e7;
-    transform: scaleX(0);
-    width: 35%;
-    transition: transform 0.3s ease-in;
-
-    &.open {
-        transform: scaleX(1);
-    }
-
-    .title {
-        background: black;
-        color: white;
-        padding: 10px 38px 10px 10px;
-        word-break: break-all;
-        margin-top: 0;
-    }
-
-    .close-details {
-        position: absolute;
-        top: 0;
-        color: white;
-        left: 0;
-        height: 21px;
-        width: 21px;
-        cursor: pointer;
-        font-size: 16px;
     }
 
     .entity-list {
@@ -397,9 +267,6 @@ g.type-TK>rect {
         text-align: left;
 
         &.deleted-relation {
-            a {
-                color: #BB5838 !important;
-            }
 
             .deleteBtn {
                 padding: 2px 8px !important;
@@ -407,27 +274,63 @@ g.type-TK>rect {
             }
         }
     }
-}
 
-.show-filter-panel,
-.show-search-panel {
-    right: 0px !important;
-}
 
+    .header {
+        background: $color_havelock_blue_approx;
+        color: white;
+        position: relative;
+        text-align: center;
+        width: 100%;
+        position: sticky;
+        height: 37px;
+        top: 0;
+        z-index: 999;
+
+        >h4 {
+            padding: 0px 36px 0px 10px;
+            word-break: break-all;
+        }
+
+        .btn-close {
+            position: absolute;
+            right: 0px;
+            top: 0px;
+            font-size: 18px;
+
+            &:hover {
+                color: $white;
+            }
+        }
+    }
+
+    .body {
+        padding: 10px;
+        width: 100%;
+        position: relative;
+        height: calc(100% - 37px);
+        overflow: hidden;
+    }
+}
 
 .btn-gray {
     border: 1px solid #686868;
     color: $dark_gray;
     background: white;
-}
 
-.btn-gray:hover {
-    border: 1px solid #686868;
-    color: $dark_gray !important;
-    background-color: white !important;
+    &[disabled] {
+        opacity: .3;
+    }
+
+    &:hover {
+        border: 1px solid #686868;
+        color: $dark_gray !important;
+        background-color: white !important;
+    }
 }
 
 
+
 span#zoom_in {
     border-bottom: 1px solid #625555;
 }
@@ -445,6 +348,11 @@ span#zoom_in {
     position: relative;
     width: 100%;
     height: 64vh;
+    overflow: hidden !important;
+
+    &.auto-height {
+        height: auto !important;
+    }
 }
 
 .active.fullscreen-mode {
@@ -471,4 +379,56 @@ span#zoom_in {
     .lineage-box {
         padding: 10px !important;
     }
+
+    .box-panel {
+        margin: 10px !important;
+    }
+}
+
+@keyframes zoominoutsinglefeatured {
+    0% {
+        transform: scale(1, 1);
+    }
+
+    50% {
+        transform: scale(1.2, 1.2);
+    }
+
+    100% {
+        transform: scale(1, 1);
+    }
+}
+
+.wobble {
+    animation: zoominoutsinglefeatured 1s 5;
+}
+
+.hover {
+
+    g.node {
+        opacity: 0.1 !important;
+    }
+
+    g.edgePath {
+        opacity: 0 !important;
+    }
+
+    g.node.hover-active,
+    g.edgePath.hover-active-node {
+        opacity: 1 !important;
+    }
+}
+
+.lineage-node-detail {
+    .table-quickMenu {
+        td:nth-child(1n) {
+            width: 150px;
+        }
+
+        word-break: break-all;
+    }
+}
+
+.hidden-svg {
+    visibility: hidden;
 }
\ No newline at end of file
diff --git a/dashboardv2/public/css/scss/override.scss b/dashboardv2/public/css/scss/override.scss
index 089393e..bf3a513 100644
--- a/dashboardv2/public/css/scss/override.scss
+++ b/dashboardv2/public/css/scss/override.scss
@@ -48,7 +48,7 @@
 .modal-body {
     position: relative;
     padding: 15px;
-    max-height: 400px;
+    max-height: 72vh;
     min-height: 70px;
     overflow: auto;
     .btn+.btn {
diff --git a/dashboardv2/public/img/entity-icon/disabled/falcon_feed_creation.png b/dashboardv2/public/img/entity-icon/disabled/falcon_feed_creation.png
new file mode 100644
index 0000000..b98be6c
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/falcon_feed_creation.png differ
diff --git a/dashboardv2/public/img/entity-icon/disabled/falcon_feed_replication.png b/dashboardv2/public/img/entity-icon/disabled/falcon_feed_replication.png
new file mode 100644
index 0000000..b98be6c
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/falcon_feed_replication.png differ
diff --git a/dashboardv2/public/img/entity-icon/disabled/falcon_process.png b/dashboardv2/public/img/entity-icon/disabled/falcon_process.png
new file mode 100644
index 0000000..b98be6c
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/falcon_process.png differ
diff --git a/dashboardv2/public/img/entity-icon/disabled/impala_column_lineage_disabled.png b/dashboardv2/public/img/entity-icon/disabled/impala_column_lineage_disabled.png
new file mode 100755
index 0000000..3b9b8cb
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/impala_column_lineage_disabled.png differ
diff --git a/dashboardv2/public/img/entity-icon/disabled/impala_process_disabled.png b/dashboardv2/public/img/entity-icon/disabled/impala_process_disabled.png
new file mode 100755
index 0000000..a207acb
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/disabled/impala_process_disabled.png differ
diff --git a/dashboardv2/public/img/entity-icon/falcon_feed_creation.png b/dashboardv2/public/img/entity-icon/falcon_feed_creation.png
new file mode 100644
index 0000000..ddb3829
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/falcon_feed_creation.png differ
diff --git a/dashboardv2/public/img/entity-icon/falcon_feed_replication.png b/dashboardv2/public/img/entity-icon/falcon_feed_replication.png
new file mode 100644
index 0000000..ddb3829
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/falcon_feed_replication.png differ
diff --git a/dashboardv2/public/img/entity-icon/falcon_process.png b/dashboardv2/public/img/entity-icon/falcon_process.png
new file mode 100644
index 0000000..ddb3829
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/falcon_process.png differ
diff --git a/dashboardv2/public/img/entity-icon/impala_column_lineage.png b/dashboardv2/public/img/entity-icon/impala_column_lineage.png
new file mode 100755
index 0000000..453ac96
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/impala_column_lineage.png differ
diff --git a/dashboardv2/public/img/entity-icon/impala_process.png b/dashboardv2/public/img/entity-icon/impala_process.png
new file mode 100755
index 0000000..c5e17c5
Binary files /dev/null and b/dashboardv2/public/img/entity-icon/impala_process.png differ
diff --git a/dashboardv2/public/img/icon-gear-active.png b/dashboardv2/public/img/icon-gear-active.png
deleted file mode 100644
index 7dffb90..0000000
Binary files a/dashboardv2/public/img/icon-gear-active.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-gear-delete.png b/dashboardv2/public/img/icon-gear-delete.png
deleted file mode 100644
index 90590fc..0000000
Binary files a/dashboardv2/public/img/icon-gear-delete.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-gear.png b/dashboardv2/public/img/icon-gear.png
deleted file mode 100644
index dc935e9..0000000
Binary files a/dashboardv2/public/img/icon-gear.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-table-active.png b/dashboardv2/public/img/icon-table-active.png
deleted file mode 100644
index 4427a05..0000000
Binary files a/dashboardv2/public/img/icon-table-active.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-table-delete.png b/dashboardv2/public/img/icon-table-delete.png
deleted file mode 100644
index 67a6c8f..0000000
Binary files a/dashboardv2/public/img/icon-table-delete.png and /dev/null differ
diff --git a/dashboardv2/public/img/icon-table.png b/dashboardv2/public/img/icon-table.png
deleted file mode 100644
index 1b1e4f0..0000000
Binary files a/dashboardv2/public/img/icon-table.png and /dev/null differ
diff --git a/dashboardv2/public/js/main.js b/dashboardv2/public/js/main.js
index 389ed5b..6c2dded 100644
--- a/dashboardv2/public/js/main.js
+++ b/dashboardv2/public/js/main.js
@@ -174,6 +174,7 @@ require.config({
 
 require(['App',
     'router/Router',
+    'utils/Helper',
     'utils/CommonViewFunction',
     'utils/Globals',
     'utils/UrlLinks',
@@ -183,7 +184,7 @@ require(['App',
     'bootstrap',
     'd3',
     'select2'
-], function(App, Router, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList) {
+], function(App, Router, Helper, CommonViewFunction, Globals, UrlLinks, VEntityList, VTagList) {
     var that = this;
     this.asyncFetchCounter = 5;
     this.entityDefCollection = new VEntityList();
diff --git a/dashboardv2/public/js/router/Router.js b/dashboardv2/public/js/router/Router.js
index d90c901..13f8704 100644
--- a/dashboardv2/public/js/router/Router.js
+++ b/dashboardv2/public/js/router/Router.js
@@ -104,6 +104,7 @@ define([
             this.postRouteExecute();
         },
         preRouteExecute: function() {
+            $(".tooltip").tooltip("hide");
             // console.log("Pre-Route Change Operations can be performed here !!");
         },
         postRouteExecute: function(name, args) {
diff --git a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html
index 2c92103..8679c3b 100644
--- a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html
@@ -16,10 +16,10 @@
 -->
 <!-- <div class="graph-toolbar clearfix"></div> -->
 <div class="white-bg no-padding lineage-box">
-    <div class="lineage-fltr-panel">
+    <div class="box-panel filter-box">
         <div class="header clearfix">
             <h4>Filters</h4>
-            <span data-id="fltr-togler" style="margin: 7px" class="btn btn-action btn-sm fltr-togler"><i class="fa fa-close"></i></span>
+            <span data-id="box-close" class="btn btn-sm btn-close"><i class="fa fa-close"></i></span>
         </div>
         <div class="body">
             <div class="hideProcessContainer form-group text-left col-sm-12">
@@ -46,31 +46,102 @@
             </div>
         </div>
     </div>
+    <div class="box-panel search-box">
+        <div class="header clearfix">
+            <h4>Search</h4>
+            <span data-id="box-close" class="btn btn-sm btn-close"><i class="fa fa-close"></i></span>
+        </div>
+        <div class="body">
+            <div class="col-sm-12 no-padding">
+                <div class="srchType clearfix">
+                    <label class="srchTitle">Search Lineage Entity: </label>
+                    <div class="">
+                        <div class="col-sm-12 no-padding temFilter">
+                            <select data-id="typeSearch"></select>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="box-panel setting-box">
+        <div class="header clearfix">
+            <h4>Settings</h4>
+            <span data-id="box-close" class="btn btn-sm btn-close"><i class="fa fa-close"></i></span>
+        </div>
+        <div class="body">
+            <div class="showOnlyHoverPath form-group text-left col-sm-12">
+                <div class="pretty p-switch p-fill">
+                    <input type="checkbox" checked class="pull-left" data-id="showOnlyHoverPath" value="" />
+                    <div class="state p-primary">
+                        <label>On hover show current path</label>
+                    </div>
+                </div>
+            </div>
+            <div class="showTooltip form-group text-left col-sm-12">
+                <div class="pretty p-switch p-fill">
+                    <input type="checkbox" class="pull-left" data-id="showTooltip" value="" />
+                    <div class="state p-primary">
+                        <label>Show node details on hover</label>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
     <div class="graph-button-group pull-right">
         <div>
-            <button type="button" data-id="fltr-togler" class="btn btn-action btn-gray btn-sm"><i class="fa fa-filter"></i></button>
+            <button data-id="resetLineage" class="btn btn-action btn-gray btn-sm" title="Realign Lineage">
+                <i class="fa fa-retweet"></i>
+            </button>
+        </div>
+        <div>
+            <button data-id="saveSvg" class="btn btn-action btn-gray btn-sm" title="Export to PNG">
+                <i class="fa fa-camera"></i>
+            </button>
+        </div>
+        <div>
+            <button type="button" data-id="setting-toggler" title="Settings" class="btn btn-action btn-gray btn-sm"><i class="fa fa-gear"></i></button>
+        </div>
+        <div>
+            <button type="button" data-id="filter-toggler" title="Filter" class="btn btn-action btn-gray btn-sm"><i class="fa fa-filter"></i></button>
         </div>
         <div>
-            <button type="button" data-id="fullScreen-toggler" class="btn btn-action btn-gray btn-sm fullscreen_lineage"><i class="fa fa-expand"></i></button>
+            <button type="button" data-id="search-toggler" title="Search" class="btn btn-action btn-gray btn-sm"><i class="fa fa-search"></i></button>
         </div>
         <div class="btn-group">
             <button type="button" id="zoom_in" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom In" data-id="refreshBtn"> <i class="fa fa-search-plus"></i></button>
             <button type="button" id="zoom_out" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom Out" data-id="refreshBtn"> <i class="fa fa-search-minus"></i></button>
         </div>
+        <div>
+            <button type="button" data-id="fullScreen-toggler" title="Full screen" class="btn btn-action btn-gray btn-sm fullscreen_lineage"><i class="fa fa-expand"></i></button>
+        </div>
+    </div>
+    <div class="box-panel size-lg node-details slide-from-left lineage-node-detail">
+        <div class="header clearfix">
+            <h4><span data-id="typeName"></span></h4>
+            <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span>
+            <span data-id="box-close" class="btn btn-sm btn-close lineage-node-detail-close"><i class="fa fa-close"></i></span>
+        </div>
+        <div class="body">
+            <table class='table table-quickMenu'>
+                <thead>
+                    <tr>
+                        <th>Key</th>
+                        <th>Value</th>
+                    </tr>
+                </thead>
+                <tbody data-id="nodeDetailTable"></tbody>
+            </table>
+        </div>
     </div>
     <div class="fontLoader">
         <i class="fa fa-refresh fa-spin-custom"></i>
     </div>
     <div class="legends pull-left" style="height: 25px; padding: 2px;">
-        <span style="margin-right: 8px; color:#fb4200;"><i class="fa fa-circle-o fa-fw" aria-hidden="true"></i>Current Entity</span>
-        <span style="margin-right: 8px; color:#df9b00;"><i class="fa fa-long-arrow-right fa-fw" aria-hidden="true"></i>Lineage</span>
-        <span style="margin-right: 8px; color:#fb4200;"><i class="fa fa-long-arrow-right fa-fw" aria-hidden="true"></i>Impact</span>
-    </div>
-    <svg width="100%" height="calc(100% - 28px)" viewBox="0 0 854 330" enable-background="new 0 0 854 330" xml:space="preserve"></svg>
-    <div class="lineage-details node-details">
-        <span data-id="close" style="margin: 7px;position: absolute;right: 0" class="btn btn-action btn-sm fltr-togler"><i class="fa fa-close"></i></span>
-        <h4 class="title"><span data-id="typeName"></span></h4>
-        <div class="col-md-12" data-id="entityList">
-        </div>
+        <span style="margin-right: 8px; color:#fb4200;"><i class="fa fa-circle-o fa-fw"></i>Current Entity</span>
+        <span style="margin-right: 8px; color:#df9b00;"><i class="fa fa-long-arrow-right fa-fw"></i>Lineage</span>
+        <span style="margin-right: 8px; color:#fb4200;"><i class="fa fa-long-arrow-right fa-fw"></i>Impact</span>
     </div>
-</div>
\ No newline at end of file
+    <svg width="{{width}}" height="{{height}}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"></svg>
+</div>
+<div class="hidden-svg"></div>
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/Helper.js b/dashboardv2/public/js/utils/Helper.js
new file mode 100644
index 0000000..f93b88b
--- /dev/null
+++ b/dashboardv2/public/js/utils/Helper.js
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+define(['require',
+    'utils/Utils',
+    'marionette'
+], function(require, Utils) {
+    'use strict';
+    _.mixin({
+        isEmptyArray: function(val) {
+            if (val && _.isArray(val)) {
+                return _.isEmpty(val);
+            } else {
+                return false;
+            }
+        },
+        toArrayifObject: function(val) {
+            return _.isObject(val) ? [val] : val;
+        },
+        startsWith: function(str, matchStr) {
+            if (str && matchStr && _.isString(str) && _.isString(matchStr)) {
+                return str.lastIndexOf(matchStr, 0) === 0
+            } else {
+                return;
+            }
+        },
+        isUndefinedNull: function(val) {
+            if (_.isUndefined(val) || _.isNull(val)) {
+                return true
+            } else {
+                return false;
+            }
+        },
+        trim: function(val) {
+            if (val && val.trim) {
+                return val.trim();
+            } else {
+                return val;
+            }
+        },
+        isTypePrimitive: function(type) {
+            if (type === "int" || type === "byte" || type === "short" || type === "long" || type === "float" || type === "double" || type === "string" || type === "boolean" || type === "date") {
+                return true;
+            }
+            return false;
+        }
+    });
+    var getPopoverEl = function(e) {
+        return $(e.target).parent().data("bs.popover") || $(e.target).data("bs.popover") || $(e.target).parents('.popover').length;
+    }
+    $(document).on('click DOMMouseScroll mousewheel', function(e) {
+        if (e.originalEvent) {
+            // Do action if it is triggered by a human.
+            //e.isImmediatePropagationStopped();
+            var isPopOverEl = getPopoverEl(e)
+            if (!isPopOverEl) {
+                $('.popover').popover('hide');
+            } else if (isPopOverEl.$tip) {
+                $('.popover').not(isPopOverEl.$tip).popover('hide');
+            }
+        }
+    });
+    $('body').on('hidden.bs.popover', function(e) {
+        $(e.target).data("bs.popover").inState = { click: false, hover: false, focus: false }
+    });
+    $('body').on('show.bs.popover', '[data-js="popover"]', function() {
+        $('.popover').not(this).popover('hide');
+    });
+    $('body').on('keypress', 'input.number-input,.number-input .select2-search__field', function(e) {
+        if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
+            return false;
+        }
+    });
+    $('body').on('keypress', 'input.number-input-negative,.number-input-negative .select2-search__field', function(e) {
+        if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
+            if (e.which == 45) {
+                if (this.value.length) {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+        }
+    });
+    $('body').on('keypress', 'input.number-input-exponential,.number-input-exponential .select2-search__field', function(e) {
+        if ((e.which != 8 && e.which != 0) && (e.which < 48 || e.which > 57) && (e.which != 69 && e.which != 101 && e.which != 43 && e.which != 45 && e.which != 46 && e.which != 190)) {
+            return false;
+        }
+    });
+    $("body").on('click', '.dropdown-menu.dropdown-changetitle li a', function() {
+        $(this).parents('li').find(".btn:first-child").html($(this).text() + ' <span class="caret"></span>');
+    });
+    $("body").on('click', '.btn', function() {
+        $(this).blur();
+    });
+
+    // For placeholder support 
+    if (!('placeholder' in HTMLInputElement.prototype)) {
+        var originalRender = Backbone.Marionette.LayoutView.prototype.render;
+        Backbone.Marionette.LayoutView.prototype.render = function() {
+            originalRender.apply(this, arguments);
+            this.$('input, textarea').placeholder();
+        }
+    }    
+    $('body').on('click', 'pre.code-block .expand-collapse-button', function(e) {
+        var $el = $(this).parents('.code-block');
+        if ($el.hasClass('shrink')) {
+            $el.removeClass('shrink');
+        } else {
+            $el.addClass('shrink');
+        }
+    });
+
+    // For adding tooltip globally
+    $('body').tooltip({
+        selector: '[title]',
+        placement: 'bottom',
+        container: 'body'
+    });
+
+})
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/Overrides.js b/dashboardv2/public/js/utils/Overrides.js
index d49a5fc..61c9595 100644
--- a/dashboardv2/public/js/utils/Overrides.js
+++ b/dashboardv2/public/js/utils/Overrides.js
@@ -49,81 +49,6 @@ define(['require', 'utils/Utils', 'marionette', 'backgrid', 'asBreadcrumbs', 'jq
         ]);
     }
 
-    _.mixin({
-        isEmptyArray: function(val) {
-            if (val && _.isArray(val)) {
-                return _.isEmpty(val);
-            } else {
-                return false;
-            }
-        },
-        isUndefinedNull: function(val) {
-            if (_.isUndefined(val) || _.isNull(val)) {
-                return true
-            } else {
-                return false;
-            }
-        },
-        trim: function(val) {
-            if (val && val.trim) {
-                return val.trim();
-            } else {
-                return val;
-            }
-        }
-    });
-    var getPopoverEl = function(e) {
-        return $(e.target).parent().data("bs.popover") || $(e.target).data("bs.popover") || $(e.target).parents('.popover').length;
-    }
-    $('body').on('click DOMMouseScroll mousewheel', function(e) {
-        if (e.originalEvent) {
-            // Do action if it is triggered by a human.
-            //e.isImmediatePropagationStopped();
-            var isPopOverEl = getPopoverEl(e)
-            if (!isPopOverEl) {
-                $('.popover').popover('hide');
-            } else if (isPopOverEl.$tip) {
-                $('.popover').not(isPopOverEl.$tip).popover('hide');
-            }
-        }
-    });
-    $('body').on('hidden.bs.popover', function(e) {
-        $(e.target).data("bs.popover").inState = { click: false, hover: false, focus: false }
-    });
-    $('body').on('show.bs.popover', '[data-js="popover"]', function() {
-        $('.popover').not(this).popover('hide');
-    });
-    $('body').on('keypress', 'input.number-input,.number-input .select2-search__field', function(e) {
-        if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
-            return false;
-        }
-    });
-    $('body').on('keypress', 'input.number-input-negative,.number-input-negative .select2-search__field', function(e) {
-        if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
-            if (e.which == 45) {
-                if (this.value.length) {
-                    return false;
-                }
-            } else {
-                return false;
-            }
-        }
-    });
-    $('body').on('keypress', 'input.number-input-exponential,.number-input-exponential .select2-search__field', function(e) {
-        if ((e.which != 8 && e.which != 0) && (e.which < 48 || e.which > 57) && (e.which != 69 && e.which != 101 && e.which != 43 && e.which != 45 && e.which != 46 && e.which != 190)) {
-            return false;
-        }
-    });
-
-    // For placeholder support 
-    if (!('placeholder' in HTMLInputElement.prototype)) {
-        var originalRender = Backbone.Marionette.LayoutView.prototype.render;
-        Backbone.Marionette.LayoutView.prototype.render = function() {
-            originalRender.apply(this, arguments);
-            this.$('input, textarea').placeholder();
-        }
-    }
-
     String.prototype.trunc = String.prototype.trunc ||
         function(n) {
             return (this.length > n) ? this.substr(0, n - 1) + '...' : this;
diff --git a/dashboardv2/public/js/utils/Utils.js b/dashboardv2/public/js/utils/Utils.js
index 5e90972..81dc953 100644
--- a/dashboardv2/public/js/utils/Utils.js
+++ b/dashboardv2/public/js/utils/Utils.js
@@ -768,14 +768,5 @@ define(['require', 'utils/Globals', 'pnotify', 'utils/Messages', 'utils/Enums',
             this.attr(attributeName, firstString);
         }
     }
-
-    $('body').on('click', 'pre.code-block .expand-collapse-button', function(e) {
-        var $el = $(this).parents('.code-block');
-        if ($el.hasClass('shrink')) {
-            $el.removeClass('shrink');
-        } else {
-            $el.addClass('shrink');
-        }
-    });
     return Utils;
 });
\ No newline at end of file
diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
index 685fcac..6faa8a8 100644
--- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
@@ -336,9 +336,9 @@ define(['require',
                 _.each(tagObject, function(val) {
                     var checkTagOrTerm = Utils.checkTagOrTerm(val);
                     if (checkTagOrTerm.term) {
-                        termData += '<span class="btn btn-action btn-sm btn-blue btn-icon term" data-id="tagClick" data-href="' + val.typeName + '"><span>' + val.typeName + '</span><i class="fa fa-close" data-id="deleteTag" data-type="term"></i></span>';
+                        termData += '<span class="btn btn-action btn-sm btn-blue btn-icon term" data-id="tagClick" data-href="' + val.typeName + '"><span title="' + val.typeName + '">' + val.typeName + '</span><i class="fa fa-close" title="Delete Term" data-id="deleteTag" data-type="term"></i></span>';
                     } else {
-                        tagData += '<span class="btn btn-action btn-sm btn-icon btn-blue" data-id="tagClick"><span>' + val.typeName + '</span><i class="fa fa-close" data-id="deleteTag" data-type="tag"></i></span>';
+                        tagData += '<span class="btn btn-action btn-sm btn-icon btn-blue" data-id="tagClick"><span title="' + val.typeName + '">' + val.typeName + '</span><i class="fa fa-close" title="Delete Tag" data-id="deleteTag" data-type="tag"></i></span>';
                     }
                 });
                 this.ui.tagList.find("span.btn").remove();
diff --git a/dashboardv2/public/js/views/graph/LineageLayoutView.js b/dashboardv2/public/js/views/graph/LineageLayoutView.js
index 5ba2f2f..881a059 100644
--- a/dashboardv2/public/js/views/graph/LineageLayoutView.js
+++ b/dashboardv2/public/js/views/graph/LineageLayoutView.js
@@ -22,14 +22,16 @@ define(['require',
     'collection/VLineageList',
     'models/VEntity',
     'utils/Utils',
+    'views/graph/LineageUtils',
     'dagreD3',
     'd3-tip',
     'utils/Enums',
     'utils/UrlLinks',
     'utils/Globals',
+    'utils/CommonViewFunction',
     'platform',
     'jquery-ui'
-], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, dagreD3, d3Tip, Enums, UrlLinks, Globals, platform) {
+], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, LineageUtils, dagreD3, d3Tip, Enums, UrlLinks, Globals, CommonViewFunction, platform) {
     'use strict';
 
     var LineageLayoutView = Backbone.Marionette.LayoutView.extend(
@@ -49,24 +51,41 @@ define(['require',
                 checkHideProcess: "[data-id='checkHideProcess']",
                 checkDeletedEntity: "[data-id='checkDeletedEntity']",
                 selectDepth: 'select[data-id="selectDepth"]',
-                fltrTogler: '[data-id="fltr-togler"]',
-                lineageFilterPanel: '.lineage-fltr-panel',
-                LineageFullscreenToggler: '[data-id="fullScreen-toggler"]',
-                lineageDetailClose: '[data-id="close"]',
-                nodeEntityList: '[data-id="entityList"]'
+                filterToggler: '[data-id="filter-toggler"]',
+                settingToggler: '[data-id="setting-toggler"]',
+                searchToggler: '[data-id="search-toggler"]',
+                boxClose: '[data-id="box-close"]',
+                lineageFullscreenToggler: '[data-id="fullScreen-toggler"]',
+                filterBox: '.filter-box',
+                searchBox: '.search-box',
+                settingBox: '.setting-box',
+                lineageTypeSearch: '[data-id="typeSearch"]',
+                searchNode: '[data-id="searchNode"]',
+                nodeDetailTable: '[data-id="nodeDetailTable"]',
+                showOnlyHoverPath: '[data-id="showOnlyHoverPath"]',
+                showTooltip: '[data-id="showTooltip"]',
+                saveSvg: '[data-id="saveSvg"]',
+                resetLineage: '[data-id="resetLineage"]'
+            },
+            templateHelpers: function() {
+                return {
+                    width: "100%",
+                    height: "100%"
+                };
             },
-
             /** ui events hash */
             events: function() {
                 var events = {};
                 events["click " + this.ui.checkHideProcess] = 'onCheckUnwantedEntity';
                 events["click " + this.ui.checkDeletedEntity] = 'onCheckUnwantedEntity';
                 events['change ' + this.ui.selectDepth] = 'onSelectDepthChange';
-                events["click " + this.ui.fltrTogler] = 'onClickFiltrTogler';
-                events["click " + this.ui.LineageFullscreenToggler] = 'onClickLineageFullscreenToggler';
-                events["click " + this.ui.lineageDetailClose] = function() {
-                    this.toggleLineageInfomationSlider({ close: true });
-                };
+                events["click " + this.ui.filterToggler] = 'onClickFilterToggler';
+                events["click " + this.ui.boxClose] = 'toggleBoxPanel';
+                events["click " + this.ui.settingToggler] = 'onClickSettingToggler';
+                events["click " + this.ui.lineageFullscreenToggler] = 'onClickLineageFullscreenToggler';
+                events["click " + this.ui.searchToggler] = 'onClickSearchToggler';
+                events["click " + this.ui.saveSvg] = 'onClickSaveSvg';
+                events["click " + this.ui.resetLineage] = 'onClickResetLineage';
                 return events;
             },
 
@@ -75,18 +94,20 @@ define(['require',
              * @constructs
              */
             initialize: function(options) {
-                _.extend(this, _.pick(options, 'processCheck', 'guid', 'entityDefCollection', 'actionCallBack', 'fetchCollection'));
+                _.extend(this, _.pick(options, 'processCheck', 'guid', 'entity', 'entityName', 'entityDefCollection', 'actionCallBack', 'fetchCollection', 'attributeDefs'));
                 this.collection = new VLineageList();
                 this.lineageData = null;
                 this.typeMap = {};
                 this.apiGuid = {};
-                this.asyncFetchCounter = 0;
                 this.edgeCall;
                 this.filterObj = {
                     isProcessHideCheck: false,
                     isDeletedEntityHideCheck: false,
                     depthCount: ''
                 };
+                this.searchNodeObj = {
+                    selectedNode: ''
+                }
             },
 
             initializeGraph: function() {
@@ -106,12 +127,19 @@ define(['require',
                         return {};
                     });
             },
-
             onRender: function() {
                 var that = this;
                 this.fetchGraphData();
+
+
                 if (platform.name === "IE") {
                     this.$('svg').css('opacity', '0');
+
+                }
+
+                if (platform.name === "Microsoft Edge" || platform.name === "IE") {
+                    $(that.ui.saveSvg).hide();
+
                 }
                 if (this.layoutRendered) {
                     this.layoutRendered();
@@ -141,22 +169,45 @@ define(['require',
                 var icon = $(e.currentTarget).find('i'),
                     panel = $(e.target).parents('.tab-pane').first();
                 icon.toggleClass('fa-expand fa-compress');
+                if (icon.hasClass('fa-expand')) {
+                    icon.parent('button').attr("data-original-title", "Full Screen");
+                } else {
+                    icon.parent('button').attr("data-original-title", "Default View");
+                }
                 panel.toggleClass('fullscreen-mode');
             },
             onCheckUnwantedEntity: function(e) {
                 var data = $.extend(true, {}, this.lineageData);
-                this.fromToObj = {};
+                //this.fromToNodeData = {};
                 this.initializeGraph();
                 if ($(e.target).data("id") === "checkHideProcess") {
                     this.filterObj.isProcessHideCheck = e.target.checked;
                 } else {
                     this.filterObj.isDeletedEntityHideCheck = e.target.checked;
                 }
-                this.generateData(data.relations, data.guidEntityMap);
+                this.generateData({ "relationshipMap": this.relationshipMap, "guidEntityMap": this.guidEntityMap });
+            },
+            toggleBoxPanel: function(options) {
+                var el = options && options.el,
+                    nodeDetailToggler = options && options.nodeDetailToggler,
+                    currentTarget = options.currentTarget;
+                this.$el.find('.show-box-panel').removeClass('show-box-panel');
+                if (el && el.addClass) {
+                    el.addClass('show-box-panel');
+                }
+                this.$('circle.node-detail-highlight').removeClass("node-detail-highlight");
+            },
+            onClickNodeToggler: function(options) {
+                this.toggleBoxPanel({ el: this.$('.lineage-node-detail'), nodeDetailToggler: true });
+            },
+            onClickFilterToggler: function() {
+                this.toggleBoxPanel({ el: this.ui.filterBox });
+            },
+            onClickSettingToggler: function() {
+                this.toggleBoxPanel({ el: this.ui.settingBox });
             },
-            onClickFiltrTogler: function() {
-                var lineageFilterPanel = this.ui.lineageFilterPanel;
-                $(lineageFilterPanel).toggleClass("show-filter-panel");
+            onClickSearchToggler: function() {
+                this.toggleBoxPanel({ el: this.ui.searchBox });
             },
             onSelectDepthChange: function(e, options) {
                 this.initializeGraph();
@@ -167,19 +218,28 @@ define(['require',
             fetchGraphData: function(options) {
                 var that = this,
                     queryParam = options && options.queryParam || {};
-                this.fromToObj = {};
+                this.fromToNodeData = {};
                 this.$('.fontLoader').show();
                 this.$('svg>g').hide();
+                this.toggleDisableState({
+                    "el": that.$(".graph-button-group button,select[data-id='selectDepth']")
+                });
                 this.collection.getLineage(this.guid, {
                     skipDefaultError: true,
                     queryParam: queryParam,
                     success: function(data) {
                         if (data.relations.length) {
-                            that.lineageData = $.extend(true, {}, data)
-                            that.generateData(data.relations, data.guidEntityMap);
+                            that.lineageData = $.extend(true, {}, data);
+                            that.relationshipMap = that.crateLineageRelationshipHashMap(data);
+                            that.guidEntityMap = $.extend(true, {}, data.guidEntityMap);
+                            that.generateData({ "relationshipMap": that.relationshipMap, "guidEntityMap": that.guidEntityMap });
+                            that.toggleDisableState({
+                                "el": that.$(".graph-button-group button,select[data-id='selectDepth']")
+                            });
                         } else {
                             that.noLineage();
                             that.hideCheckForProcess();
+
                         }
                     },
                     cust_error: function(model, response) {
@@ -195,7 +255,6 @@ define(['require',
             noLineage: function() {
                 this.$('.fontLoader').hide();
                 this.$('.depth-container').hide();
-                //this.$('svg').height('100');
                 this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No lineage data found</text>');
                 if (this.actionCallBack) {
                     this.actionCallBack();
@@ -204,210 +263,257 @@ define(['require',
             hideCheckForProcess: function() {
                 this.$('.hideProcessContainer').hide();
             },
-            generateData: function(relations, guidEntityMap) {
-                var that = this;
-
-                function isProcess(node) {
-                    if (_.isUndefined(node) || node.typeName == "Process") {
-                        return true;
-                    }
-                    var entityDef = that.entityDefCollection.fullCollection.find({ name: node.typeName });
-                    return _.contains(Utils.getNestedSuperTypes({ data: entityDef.toJSON(), collection: that.entityDefCollection }), "Process")
+            isProcess: function(node) {
+                var typeName = node.typeName,
+                    superTypes = node.superTypes,
+                    entityDef = node.entityDef;
+                if (typeName == "Process") {
+                    return true;
                 }
-
-                function isDeleted(node) {
-                    if (_.isUndefined(node)) {
-                        return
-                    }
-                    return Enums.entityStateReadOnly[node.status];
+                return _.contains(superTypes, "Process");
+            },
+            isDeleted: function(node) {
+                if (_.isUndefined(node)) {
+                    return
                 }
+                return Enums.entityStateReadOnly[node.status];
+            },
+            isNodeToBeUpdated: function(node) {
+                var isProcessHideCheck = this.filterObj.isProcessHideCheck,
+                    isDeletedEntityHideCheck = this.filterObj.isDeletedEntityHideCheck
+                var returnObj = {
+                    isProcess: (isProcessHideCheck && node.isProcess),
+                    isDeleted: (isDeletedEntityHideCheck && node.isDeleted)
 
-                function isNodeToBeUpdated(node) {
-                    var isProcessHideCheck = that.filterObj.isProcessHideCheck,
-                        isDeletedEntityHideCheck = that.filterObj.isDeletedEntityHideCheck
-                    var returnObj = {
-                        isProcess: (isProcessHideCheck && isProcess(node)),
-                        isDeleted: (isDeletedEntityHideCheck && isDeleted(node))
-
-                    };
-                    returnObj["update"] = returnObj.isProcess || returnObj.isDeleted;
-                    return returnObj;
+                };
+                returnObj["update"] = returnObj.isProcess || returnObj.isDeleted;
+                return returnObj;
+            },
+            getNestedSuperTypes: function(options) {
+                var entityDef = options.entityDef;
+                return Utils.getNestedSuperTypes({ data: entityDef, collection: this.entityDefCollection })
+            },
+            getEntityDef: function(typeName) {
+                var entityDef = null;
+                if (typeName) {
+                    entityDef = this.entityDefCollection.fullCollection.find({ name: typeName });
+                    entityDef = entityDef ? entityDef.toJSON() : entityDef;
                 }
-
-                function getServiceType(typeName) {
-                    var serviceType = null;
-                    if (typeName) {
-                        var entityDef = that.entityDefCollection.fullCollection.find({ name: typeName });
-                        if (entityDef) {
-                            serviceType = entityDef.get("serviceType") || null;
-                        }
+                return entityDef;
+            },
+            getServiceType: function(options) {
+                if (!options) {
+                    return;
+                }
+                var typeName = options.typeName,
+                    entityDef = options.entityDef,
+                    serviceType = null;
+                if (typeName) {
+                    if (entityDef) {
+                        serviceType = entityDef.serviceType || null;
                     }
-                    return serviceType;
                 }
-
-                function makeNodeObj(relationObj) {
-                    var obj = {};
-                    obj['shape'] = "img";
-                    obj['typeName'] = relationObj.typeName
-                    obj['label'] = relationObj.displayText.trunc(18);
-                    obj['toolTipLabel'] = relationObj.displayText;
-                    obj['id'] = relationObj.guid;
-                    obj['isLineage'] = true;
-                    obj['queryText'] = relationObj.queryText;
-                    obj['serviceType'] = getServiceType(relationObj.typeName);
-                    if (relationObj.status) {
-                        obj['status'] = relationObj.status;
+                return serviceType;
+            },
+            crateLineageRelationshipHashMap: function(data) {
+                var that = this,
+                    relations = data && data.relations,
+                    guidEntityMap = data && data.guidEntityMap,
+                    makeNodeData = function(relationObj) {
+                        var obj = $.extend(true, {
+                            shape: "img",
+                            label: relationObj.displayText.trunc(18),
+                            toolTipLabel: relationObj.displayText,
+                            id: relationObj.guid,
+                            isLineage: true,
+                            entityDef: this.getEntityDef(relationObj.typeName)
+                        }, relationObj);
+                        obj["serviceType"] = this.getServiceType({ typeName: relationObj.typeName, entityDef: obj.entityDef });
+                        obj["superTypes"] = this.getNestedSuperTypes({ entityDef: obj.entityDef });
+                        obj['isProcess'] = this.isProcess(obj);
+                        obj['isDeleted'] = this.isDeleted(obj);
+                        return obj;
+                    }.bind(this),
+                    newHashMap = {};
+                _.each(relations, function(obj) {
+                    if (!that.fromToNodeData[obj.fromEntityId]) {
+                        that.fromToNodeData[obj.fromEntityId] = makeNodeData(guidEntityMap[obj.fromEntityId]);
                     }
-                    if (that.filterObj.isProcessHideCheck) {
-                        obj['isProcess'] = relationObj.isProcess;
+                    if (!that.fromToNodeData[obj.toEntityId]) {
+                        that.fromToNodeData[obj.toEntityId] = makeNodeData(guidEntityMap[obj.toEntityId]);
+                    }
+                    if (newHashMap[obj.fromEntityId]) {
+                        newHashMap[obj.fromEntityId].push(obj.toEntityId);
                     } else {
-                        obj['isProcess'] = isProcess(relationObj);
+                        newHashMap[obj.fromEntityId] = [obj.toEntityId];
                     }
-
-                    return obj;
-                }
-
-                var newRelations = [],
-                    finalRelations = relations,
-                    isHideFilterOn = this.filterObj.isProcessHideCheck || this.filterObj.isDeletedEntityHideCheck;
-                if (isHideFilterOn) {
-                    _.each(relations, function(obj, index, relationArr) {
-                        var toNodeToBeUpdated = isNodeToBeUpdated(guidEntityMap[obj.toEntityId]);
-                        var fromNodeToBeUpdated = isNodeToBeUpdated(guidEntityMap[obj.fromEntityId]);
-                        if (toNodeToBeUpdated.update) {
-                            if (that.filterObj.isProcessHideCheck) {
-                                //We have already checked entity is process or not inside isNodeToBeUpdated();
-                                guidEntityMap[obj.toEntityId]["isProcess"] = true;
-                            }
-                            _.filter(relationArr, function(flrObj) {
-                                if (flrObj.fromEntityId === obj.toEntityId) {
-                                    if (that.filterObj.isDeletedEntityHideCheck && isDeleted(guidEntityMap[flrObj.toEntityId])) {
-                                        return;
+                });
+                return newHashMap;
+            },
+            generateData: function(options) {
+                var that = this,
+                    relationshipMap = options && $.extend(true, {}, options.relationshipMap) || {},
+                    guidEntityMap = options && options.guidEntityMap || {},
+                    styleObj = {
+                        fill: 'none',
+                        stroke: '#ffb203',
+                        width: 3
+                    },
+                    getStyleObjStr = function(styleObj) {
+                        return 'fill:' + styleObj.fill + ';stroke:' + styleObj.stroke + ';stroke-width:' + styleObj.width;
+                    },
+                    filterRelationshipMap = relationshipMap,
+                    isHideFilterOn = this.filterObj.isProcessHideCheck || this.filterObj.isDeletedEntityHideCheck,
+                    getNewToNodeRelationship = function(toNodeGuid) {
+                        if (toNodeGuid && relationshipMap[toNodeGuid]) {
+                            var newRelationship = [];
+                            _.each(relationshipMap[toNodeGuid], function(guid) {
+                                var nodeToBeUpdated = that.isNodeToBeUpdated(that.fromToNodeData[guid]);
+                                if (nodeToBeUpdated.update) {
+                                    var newRelation = getNewToNodeRelationship(guid);
+                                    if (newRelation) {
+                                        newRelationship = newRelationship.concat(newRelation);
                                     }
-                                    newRelations.push({
-                                        fromEntityId: obj.fromEntityId,
-                                        toEntityId: flrObj.toEntityId
-                                    });
+                                } else {
+                                    newRelationship.push(guid);
                                 }
-                            })
-                        } else if (fromNodeToBeUpdated.update) {
-                            if (that.filterObj.isProcessHideCheck) {
-                                //We have already checked entity is process or not inside isNodeToBeUpdated();
-                                guidEntityMap[obj.fromEntityId]["isProcess"] = true;
-                            }
-
-                            _.filter(relationArr, function(flrObj) {
-                                if (that.filterObj.isDeletedEntityHideCheck && isDeleted(guidEntityMap[flrObj.fromEntityId])) {
-                                    return;
-                                }
-                                if (flrObj.toEntityId === obj.fromEntityId) {
-                                    newRelations.push({
-                                        fromEntityId: flrObj.fromEntityId,
-                                        toEntityId: obj.toEntityId
-                                    });
+                            });
+                            return newRelationship;
+                        } else {
+                            return null;
+                        }
+                    },
+                    getToNodeRelation = function(toNodes, fromNodeToBeUpdated) {
+                        var toNodeRelationship = [];
+                        _.each(toNodes, function(toNodeGuid) {
+                            var toNodeToBeUpdated = that.isNodeToBeUpdated(that.fromToNodeData[toNodeGuid]);
+                            if (toNodeToBeUpdated.update) {
+                                // To node need to updated
+                                if (pendingFromRelationship[toNodeGuid]) {
+                                    toNodeRelationship = toNodeRelationship.concat(pendingFromRelationship[toNodeGuid]);
+                                } else {
+                                    var newToNodeRelationship = getNewToNodeRelationship(toNodeGuid);
+                                    if (newToNodeRelationship) {
+                                        toNodeRelationship = toNodeRelationship.concat(newToNodeRelationship);
+                                    }
                                 }
-                            })
+                            } else {
+                                //when bothe node not to be updated.
+                                toNodeRelationship.push(toNodeGuid);
+                            }
+                        });
+                        return toNodeRelationship;
+                    },
+                    pendingFromRelationship = {};
+                if (isHideFilterOn) {
+                    filterRelationshipMap = {};
+                    _.each(relationshipMap, function(toNodes, fromNodeGuid) {
+                        var fromNodeToBeUpdated = that.isNodeToBeUpdated(that.fromToNodeData[fromNodeGuid]),
+                            toNodeList = getToNodeRelation(toNodes, fromNodeToBeUpdated);
+                        if (fromNodeToBeUpdated.update) {
+                            if (pendingFromRelationship[fromNodeGuid]) {
+                                pendingFromRelationship[fromNodeGuid] = pendingFromRelationship[fromNodeGuid].concat(toNodeList);
+                            } else {
+                                pendingFromRelationship[fromNodeGuid] = toNodeList;
+                            }
                         } else {
-                            newRelations.push(obj);
+                            if (filterRelationshipMap[fromNodeGuid]) {
+                                filterRelationshipMap[fromNodeGuid] = filterRelationshipMap[fromNodeGuid].concat(toNodeList);
+                            } else {
+                                filterRelationshipMap[fromNodeGuid] = toNodeList;
+                            }
                         }
-                    });
-                    finalRelations = newRelations;
+                    })
                 }
 
-                _.each(finalRelations, function(obj, index) {
-                    if (!that.fromToObj[obj.fromEntityId]) {
-                        that.fromToObj[obj.fromEntityId] = makeNodeObj(guidEntityMap[obj.fromEntityId]);
-                        that.g.setNode(obj.fromEntityId, that.fromToObj[obj.fromEntityId]);
-                    }
-                    if (!that.fromToObj[obj.toEntityId]) {
-                        that.fromToObj[obj.toEntityId] = makeNodeObj(guidEntityMap[obj.toEntityId]);
-                        that.g.setNode(obj.toEntityId, that.fromToObj[obj.toEntityId]);
-                    }
-                    var styleObj = {
-                        fill: 'none',
-                        stroke: '#ffb203',
-                        width: 3
+                _.each(filterRelationshipMap, function(toNodesList, fromNodeGuid) {
+                    if (!that.g._nodes[fromNodeGuid]) {
+                        that.g.setNode(fromNodeGuid, that.fromToNodeData[fromNodeGuid]);
                     }
-                    that.g.setEdge(obj.fromEntityId, obj.toEntityId, { 'arrowhead': "arrowPoint", lineInterpolate: 'basis', "style": "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width + "", 'styleObj': styleObj });
-                });
+                    _.each(toNodesList, function(toNodeGuid) {
+                        if (!that.g._nodes[toNodeGuid]) {
+                            that.g.setNode(toNodeGuid, that.fromToNodeData[toNodeGuid]);
+                        }
+                        that.g.setEdge(fromNodeGuid, toNodeGuid, {
+                            "arrowhead": 'arrowPoint',
+                            "lineInterpolate": 'basis',
+                            "style": getStyleObjStr(styleObj),
+                            'styleObj': styleObj
+                        });
+                    })
+                })
+
                 //if no relations found
-                if (!finalRelations.length) {
+                if (_.isEmpty(filterRelationshipMap)) {
                     this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>');
-                } else {
-                    this.$('svg').html('<text></text>');
                 }
 
-                if (this.fromToObj[this.guid]) {
-                    this.fromToObj[this.guid]['isLineage'] = false;
-                    this.checkForLineageOrImpactFlag(finalRelations, this.guid);
-                }
-                if (this.asyncFetchCounter == 0) {
-                    this.createGraph();
+                if (this.fromToNodeData[this.guid]) {
+                    this.fromToNodeData[this.guid]['isLineage'] = false;
+                    this.findImpactNodeAndUpdateData({ "relationshipMap": filterRelationshipMap, "guid": this.guid, "getStyleObjStr": getStyleObjStr });
                 }
+                this.renderLineageTypeSearch();
+                this.createGraph();
             },
-            checkForLineageOrImpactFlag: function(relations, guid) {
+            findImpactNodeAndUpdateData: function(options) {
                 var that = this,
-                    nodeFound = _.where(relations, { 'fromEntityId': guid });
-                if (nodeFound.length) {
-                    _.each(nodeFound, function(node) {
-                        if (!node["traversed"]) {
-                            node["traversed"] = true;
-                            that.fromToObj[node.toEntityId]['isLineage'] = false;
+                    relationshipMap = options.relationshipMap,
+                    fromNodeGuid = options.guid,
+                    getStyleObjStr = options.getStyleObjStr,
+                    toNodeList = relationshipMap[fromNodeGuid];
+                if (toNodeList && toNodeList.length) {
+                    if (!relationshipMap[fromNodeGuid]["traversed"]) {
+                        relationshipMap[fromNodeGuid]["traversed"] = true;
+                        _.each(toNodeList, function(toNodeGuid) {
+                            that.fromToNodeData[toNodeGuid]['isLineage'] = false;
                             var styleObj = {
                                 fill: 'none',
                                 stroke: '#fb4200',
                                 width: 3
                             }
-                            that.g.setEdge(node.fromEntityId, node.toEntityId, { 'arrowhead': "arrowPoint", lineInterpolate: 'basis', "style": "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width + "", 'styleObj': styleObj });
-                            that.checkForLineageOrImpactFlag(relations, node.toEntityId);
-                        }
-                    });
-                }
-            },
-            toggleInformationSlider: function(options) {
-                if (options.open && !this.$('.lineage-edge-details').hasClass("open")) {
-                    this.$('.lineage-edge-details').addClass('open');
-                } else if (options.close && this.$('.lineage-edge-details').hasClass("open")) {
-                    d3.selectAll('circle').attr("stroke", "none");
-                    this.$('.lineage-edge-details').removeClass('open');
-                }
-            },
-            setGraphZoomPositionCal: function(argument) {
-                var initialScale = 1.6,
-                    svgEl = this.$('svg'),
-                    scaleEl = this.$('svg').find('>g'),
-                    translateValue = [(this.$('svg').width() - this.g.graph().width * initialScale) / 2, (this.$('svg').height() - this.g.graph().height * initialScale) / 2]
-                if (_.keys(this.g._nodes).length > 15) {
-                    initialScale = 0;
-                    this.$('svg').addClass('noScale');
-                }
-                if (svgEl.parents('.panel.panel-fullscreen').length) {
-                    translateValue = [20, 20];
-                    if (svgEl.hasClass('noScale')) {
-                        if (!scaleEl.hasClass('scaleLinage')) {
-                            scaleEl.addClass('scaleLinage');
-                            initialScale = 1.6;
-                        } else {
-                            scaleEl.removeClass('scaleLinage');
-                            initialScale = 0;
-                        }
+                            that.g.setEdge(fromNodeGuid, toNodeGuid, {
+                                "arrowhead": 'arrowPoint',
+                                "lineInterpolate": 'basis',
+                                "style": getStyleObjStr(styleObj),
+                                'styleObj': styleObj
+                            });
+                            that.findImpactNodeAndUpdateData({
+                                "relationshipMap": relationshipMap,
+                                "guid": toNodeGuid,
+                                "getStyleObjStr": getStyleObjStr
+                            });
+                        });
                     }
-                } else {
-                    scaleEl.removeClass('scaleLinage');
                 }
-                this.zoom.translate(translateValue)
-                    .scale(initialScale);
             },
             zoomed: function(that) {
                 this.$('svg').find('>g').attr("transform",
                     "translate(" + this.zoom.translate() + ")" +
                     "scale(" + this.zoom.scale() + ")"
                 );
+                LineageUtils.refreshGraphForIE({
+                    edgeEl: this.$('svg .edgePath')
+                });
+            },
+            interpolateZoom: function(translate, scale, that, zoom) {
+                return d3.transition().duration(350).tween("zoom", function() {
+                    var iTranslate = d3.interpolate(zoom.translate(), translate),
+                        iScale = d3.interpolate(zoom.scale(), scale);
+                    return function(t) {
+                        zoom
+                            .scale(iScale(t))
+                            .translate(iTranslate(t));
+                        that.zoomed();
+                    };
+                });
             },
             createGraph: function() {
                 var that = this,
                     width = this.$('svg').width(),
-                    height = this.$('svg').height();
+                    height = this.$('svg').height(),
+                    imageObject = {};
+                $('.resizeGraph').css("height", height + "px");
+
                 this.g.nodes().forEach(function(v) {
                     var node = that.g.node(v);
                     // Round the corners of the nodes
@@ -419,6 +525,8 @@ define(['require',
                 var render = new dagreD3.render();
                 // Add our custom arrow (a hollow-point)
                 render.arrows().arrowPoint = function normal(parent, id, edge, type) {
+                    var parentNode = parent && parent[0] && parent[0][0] && parent[0][0].parentNode ? parent[0][0].parentNode : parent;
+                    d3.select(parentNode).select('path.path').attr('marker-end', "url(#" + id + ")");
                     var marker = parent.append("marker")
                         .attr("id", id)
                         .attr("viewBox", "0 0 10 10")
@@ -442,9 +550,12 @@ define(['require',
                     var shapeSvg = parent.append('circle')
                         .attr('fill', 'url(#img_' + node.id + ')')
                         .attr('r', '24px')
-                        .attr('data-stroke',node.id)
+                        .attr('data-stroke', node.id)
+                        .attr('stroke-width', "2px")
                         .attr("class", "nodeImage " + (currentNode ? "currentNode" : (node.isProcess ? "process" : "node")));
-
+                    if (currentNode) {
+                        shapeSvg.attr("stroke", "#fb4200")
+                    }
                     parent.insert("defs")
                         .append("pattern")
                         .attr("x", "0%")
@@ -454,18 +565,66 @@ define(['require',
                         .attr("width", "100%")
                         .attr("height", "100%")
                         .append('image')
-                        .attr("xlink:href", function(d) {
+                        .attr("href", function(d) {
+                            var that = this;
                             if (node) {
-                                return Utils.getEntityIconPath({ entityData: node });
+                                // to check for IE-10
+                                var originLink = window.location.origin;
+                                if (platform.name === "IE") {
+                                    originLink = window.location.protocol + "//" + window.location.host;
+                                }
+                                var imageIconPath = Utils.getEntityIconPath({ entityData: node }),
+                                    imagePath = ((originLink + Utils.getBaseUrl(window.location.pathname)) + imageIconPath);
+
+                                var getImageData = function(options) {
+                                    var imagePath = options.imagePath,
+                                        ajaxOptions = {
+                                            "url": imagePath,
+                                            "method": "get",
+                                            "async": false,
+                                        }
+
+                                    if (platform.name !== "IE") {
+                                        ajaxOptions["mimeType"] = "text/plain; charset=x-user-defined";
+                                    }
+                                    $.ajax(ajaxOptions)
+                                        .always(function(data, status, xhr) {
+                                            if (data.status == 404) {
+                                                getImageData({
+                                                    "imagePath": Utils.getEntityIconPath({ entityData: node, errorUrl: imagePath }),
+                                                    "imageIconPath": imageIconPath
+                                                });
+                                            } else if (data) {
+                                                if (platform.name !== "IE") {
+                                                    imageObject[imageIconPath] = 'data:image/png;base64,' + LineageUtils.base64Encode({ "data": data });
+                                                } else {
+                                                    imageObject[imageIconPath] = imagePath;
+                                                }
+                                            }
+                                        });
+                                }
+                                if (_.keys(imageObject).indexOf(imageIconPath) === -1) {
+                                    getImageData({
+                                        "imagePath": imagePath,
+                                        "imageIconPath": imageIconPath
+                                    });
+                                }
+
+                                if (_.isUndefined(imageObject[imageIconPath])) {
+                                    // before img success
+                                    imageObject[imageIconPath] = [d3.select(that)];
+                                } else if (_.isArray(imageObject[imageIconPath])) {
+                                    // before img success
+                                    imageObject[imageIconPath].push(d3.select(that));
+                                } else {
+                                    d3.select(that).attr("xlink:href", imageObject[imageIconPath]);
+                                    return imageObject[imageIconPath];
+                                }
                             }
                         })
-                        .attr("x", currentNode ? "3" : "6")
-                        .attr("y", currentNode ? "3" : "4")
-                        .attr("width", "40")
-                        .attr("height", "40")
-                        .on("error", function() {
-                            this.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', Utils.getEntityIconPath({ entityData: node, errorUrl: this.href.baseVal }));
-                        });
+                        .attr("x", "4")
+                        .attr("y", currentNode ? "3" : "4").attr("width", "40")
+                        .attr("height", "40");
 
                     node.intersect = function(point) {
                         return dagreD3.intersect.circle(node, currentNode ? 24 : 21, point);
@@ -481,31 +640,16 @@ define(['require',
                     .attr("enable-background", "new 0 0 " + width + " " + height),
                     svgGroup = svg.append("g");
                 var zoom = this.zoom = d3.behavior.zoom()
-                    .scaleExtent([0.5, 6])
+                    .center([width / 2, height / 2])
+                    .scaleExtent([0.01, 50])
                     .on("zoom", that.zoomed.bind(this));
 
-
-                function interpolateZoom(translate, scale) {
-                    var self = this;
-                    return d3.transition().duration(350).tween("zoom", function() {
-                        var iTranslate = d3.interpolate(zoom.translate(), translate),
-                            iScale = d3.interpolate(zoom.scale(), scale);
-                        return function(t) {
-                            zoom
-                                .scale(iScale(t))
-                                .translate(iTranslate(t));
-                            that.zoomed();
-                        };
-                    });
-                }
-
                 function zoomClick() {
                     var clicked = d3.event.target,
                         direction = 1,
-                        factor = 0.2,
+                        factor = 0.5,
                         target_zoom = 1,
-                        center = [that.g.graph().width / 2, that.g.graph().height / 2],
-                        extent = zoom.scaleExtent(),
+                        center = [width / 2, height / 2],
                         translate = zoom.translate(),
                         translate0 = [],
                         l = [],
@@ -515,10 +659,6 @@ define(['require',
                     direction = (this.id === 'zoom_in') ? 1 : -1;
                     target_zoom = zoom.scale() * (1 + factor * direction);
 
-                    if (target_zoom < extent[0] || target_zoom > extent[1]) {
-                        return false;
-                    }
-
                     translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
                     view.k = target_zoom;
                     l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
@@ -526,7 +666,7 @@ define(['require',
                     view.x += center[0] - l[0];
                     view.y += center[1] - l[1];
 
-                    interpolateZoom([view.x, view.y], view.k);
+                    that.interpolateZoom([view.x, view.y], view.k, that, zoom);
                 }
                 d3.selectAll(this.$('.lineageZoomButton')).on('click', zoomClick);
                 var tooltip = d3Tip()
@@ -555,10 +695,11 @@ define(['require',
                 }
                 render(svgGroup, this.g);
                 svg.on("dblclick.zoom", null)
-                    .on("wheel.zoom", null);
+                // .on("wheel.zoom", null);
                 //change text postion 
                 svgGroup.selectAll("g.nodes g.label")
                     .attr("transform", "translate(2,-35)");
+                var waitForDoubleClick = null;
                 svgGroup.selectAll("g.nodes g.node")
                     .on('mouseenter', function(d) {
                         that.activeNode = true;
@@ -584,51 +725,72 @@ define(['require',
                         } else if ((currentELWidth.top) < 400) {
                             direction = ((currentELWidth.left) < 50) ? 'se' : 's';
                         }
-                        tooltip.direction(direction).show(d)
+                        if (that.ui.showTooltip.prop('checked')) {
+                            tooltip.direction(direction).show(d);
+                        }
+
+                        if (!that.ui.showOnlyHoverPath.prop('checked')) {
+                            return;
+                        }
+                        that.$('svg').addClass('hover');
+                        var nextNode = that.g.successors(d),
+                            previousNode = that.g.predecessors(d),
+                            nodesToHighlight = nextNode.concat(previousNode);
+                        LineageUtils.onHoverFade({
+                            opacity: 0.3,
+                            selectedNode: d,
+                            highlight: nodesToHighlight,
+                            svg: that.svg
+                        }).init();
                     })
-                    .on('dblclick', function(d) {
-                        tooltip.hide(d);
-                        Utils.setUrl({
-                            url: '#!/detailPage/' + d + '?tabActive=lineage',
-                            mergeBrowserUrl: false,
-                            trigger: true
-                        });
-                    }).on('mouseleave', function(d) {
+                    .on('mouseleave', function(d) {
                         that.activeNode = false;
                         var nodeEL = this;
                         setTimeout(function(argument) {
                             if (!(that.activeTip || that.activeNode)) {
                                 $(nodeEL).removeClass('active');
-                                tooltip.hide(d);
+                                if (that.ui.showTooltip.prop('checked')) {
+                                    tooltip.hide(d);
+                                }
                             }
-                        }, 400)
-                    }).on('click', function(d) {
+                        }, 150);
+                        if (!that.ui.showOnlyHoverPath.prop('checked')) {
+                            return;
+                        }
+                        that.$('svg').removeClass('hover');
+                        that.$('svg').removeClass('hover-active');
+                        LineageUtils.onHoverFade({
+                            opacity: 1,
+                            selectedNode: d,
+                            svg: that.svg
+                        }).init();
+                    })
+                    .on('click', function(d) {
+                        var el = this;
                         if (d3.event.defaultPrevented) return; // ignore drag
-                        that.toggleLineageInfomationSlider({ open: true, obj: d });
-                        svgGroup.selectAll('[data-stroke]').attr('stroke','none');
-                        svgGroup.selectAll('[data-stroke]').attr('stroke',function(c) {
-                            if (c == d) {
-                                return "#316132";
-                            } else {
-                                return 'none';
-                            }
-                        })
-                        that.updateRelationshipDetails({ obj: d });
+                        d3.event.preventDefault();
 
+                        if (waitForDoubleClick != null) {
+                            clearTimeout(waitForDoubleClick)
+                            waitForDoubleClick = null;
+                            tooltip.hide(d);
+                            Utils.setUrl({
+                                url: '#!/detailPage/' + d + '?tabActive=lineage',
+                                mergeBrowserUrl: false,
+                                trigger: true
+                            });
+                        } else {
+                            var currentEvent = d3.event
+                            waitForDoubleClick = setTimeout(function() {
+                                tooltip.hide(d);
+                                that.onClickNodeToggler({ obj: d });
+                                $(el).find('circle').addClass('node-detail-highlight');
+                                that.updateRelationshipDetails({ guid: d });
+                                waitForDoubleClick = null;
+                            }, 150)
+                        }
                     });
-                svgGroup.selectAll("g.edgePath path.path").on('click', function(d) {
-                    var data = { obj: _.find(that.lineageData.relations, { "fromEntityId": d.v, "toEntityId": d.w }) },
-                        relationshipId = data.obj.relationshipId;
-                    require(['views/graph/PropagationPropertyModal'], function(PropagationPropertyModal) {
-                        var view = new PropagationPropertyModal({
-                            edgeInfo: data,
-                            relationshipId: relationshipId,
-                            lineageData: that.lineageData,
-                            apiGuid: that.apiGuid,
-                            detailPageFetchCollection: that.fetchCollection
-                        });
-                    });
-                })
+
                 $('body').on('mouseover', '.d3-tip', function(el) {
                     that.activeTip = true;
                 });
@@ -639,81 +801,256 @@ define(['require',
                 });
 
                 // Center the graph
-                this.setGraphZoomPositionCal();
+                LineageUtils.centerNode({
+                    guid: that.guid,
+                    svg: that.$('svg'),
+                    g: this.g,
+                    edgeEl: $('svg .edgePath'),
+                    afterCenterZoomed: function(options) {
+                        var newScale = options.newScale,
+                            newTranslate = options.newTranslate;
+                        that.zoom.scale(newScale);
+                        that.zoom.translate(newTranslate);
+                    }
+                }).init();
                 zoom.event(svg);
-                //svg.attr('height', this.g.graph().height * initialScale + 40);
                 if (platform.name === "IE") {
-                    this.IEGraphRenderDone = 0;
-                    this.$('svg .edgePath').each(function(argument) {
-                        var childNode = $(this).find('marker');
-                        $(this).find('marker').remove();
-                        var eleRef = this;
-                        ++that.IEGraphRenderDone;
-                        setTimeout(function(argument) {
-                            $(eleRef).find('defs').append(childNode);
-                            --that.IEGraphRenderDone;
-                            if (that.IEGraphRenderDone === 0) {
-                                this.$('.fontLoader').hide();
-                                this.$('svg').fadeTo(1000, 1)
-                            }
-                        }, 1000);
+                    LineageUtils.refreshGraphForIE({
+                        edgeEl: this.$('svg .edgePath')
                     });
                 }
+                LineageUtils.DragNode({
+                    svg: this.svg,
+                    g: this.g,
+                    guid: this.guid,
+                    edgeEl: this.$('svg .edgePath')
+                }).init();
             },
-            toggleLineageInfomationSlider: function(options) {
-                if (options.open && !this.$('.lineage-details').hasClass("open")) {
-                    this.$('.lineage-details').addClass('open');
-                } else if (options.close && this.$('.lineage-details').hasClass("open")) {
-                    d3.selectAll('circle').attr("stroke", "none");
-                    this.$('.lineage-details').removeClass('open');
+            renderLineageTypeSearch: function() {
+                var that = this,
+                    lineageData = $.extend(true, {}, this.lineageData),
+                    data = [],
+                    typeStr = '<option></option>';
+                if (!_.isEmpty(lineageData)) {
+                    _.each(lineageData.guidEntityMap, function(obj, index) {
+                        var nodeData = that.fromToNodeData[obj.guid];
+                        if (that.filterObj.isProcessHideCheck && nodeData && nodeData.isProcess) {
+                            return;
+                        } else if (that.filterObj.isDeletedEntityHideCheck && nodeData && nodeData.isDeleted) {
+                            return
+                        }
+                        typeStr += '<option value="' + obj.guid + '">' + obj.attributes.name + '</option>';
+                    });
                 }
+                that.ui.lineageTypeSearch.html(typeStr);
+                this.initilizelineageTypeSearch();
             },
-            updateRelationshipDetails: function(options) {
+            initilizelineageTypeSearch: function() {
                 var that = this;
-                var lineageData;
-                for (var x in that.lineageData.guidEntityMap) {
-                    if (x == options.obj) {
-                        lineageData = that.lineageData.guidEntityMap[x]
-                    }
-                }
-                var data = lineageData,
-                    typeName = data.typeName || options.obj.name,
-                    searchString = options.searchString,
-                    listString = "";
-                this.$("[data-id='typeName']").text(typeName);
-                var getElement = function(options) {
-                    var showCofig = [
-                        "meaningNames",
-                        "meanings",
-                        "classificationNames",
-                        {
-                            "attributes": [
-                                "description",
-                                "name",
-                                "qualifiedName"
-                            ]
+                that.ui.lineageTypeSearch.select2({
+                    closeOnSelect: true,
+                    placeholder: 'Select Node'
+                }).on('change.select2', function(e) {
+                    e.stopPropagation();
+                    e.stopImmediatePropagation();
+                    d3.selectAll(".serach-rect").remove();
+                    var selectedNode = $('[data-id="typeSearch"]').val();
+                    that.searchNodeObj.selectedNode = selectedNode;
+                    LineageUtils.centerNode({
+                        guid: selectedNode,
+                        svg: $(that.svg[0]),
+                        g: that.g,
+                        edgeEl: $('svg .edgePath'),
+                        afterCenterZoomed: function(options) {
+                            var newScale = options.newScale,
+                                newTranslate = options.newTranslate;
+                            that.zoom.scale(newScale);
+                            that.zoom.translate(newTranslate);
                         }
-                    ];
-                    var tbody = '';
-                    for (var x = 0; x < showCofig.length; x++) {
-                        if (typeof showCofig[x] === "object") {
-                            _.each(showCofig[x].attributes, function(element, index, list) {
-                                var dataToShow = data.attributes[element] ? data.attributes[element] : "N/A";
-                                tbody += '<tr><td class="html-cell renderable">' + element + '</td><td  class="html-cell renderable">' + dataToShow + '</td></tr>';
-                            })
+                    }).init();
+                    that.svg.selectAll('.nodes g.label').attr('stroke', function(c, d) {
+                        if (c == selectedNode) {
+                            return "#316132";
                         } else {
-                            var dataToShow = data[showCofig[x]] ? data[showCofig[x]] : "N/A";
-                            dataToShow = dataToShow && dataToShow.length > 0 ? dataToShow : "N/A";
-                            tbody += '<tr><td class="html-cell renderable">' + showCofig[x] + '</td><td class="html-cell renderable">' + dataToShow + '</td></tr>';
+                            return 'none';
                         }
+                    });
+                    // Using jquery for selector because d3 select is not working for few process entities.
+                    d3.select($(".node#" + selectedNode)[0]).insert("rect", "circle")
+                        .attr("class", "serach-rect")
+                        .attr("x", -50)
+                        .attr("y", -27.5)
+                        .attr("width", 100)
+                        .attr("height", 55);
+                    d3.selectAll(".nodes circle").classed("wobble", function(d, i, nodes) {
+                        if (d == selectedNode) {
+                            return true;
+                        } else {
+                            return false;
+                        }
+                    });
+
+                });
+                if (that.searchNodeObj.selectedNode) {
+                    that.ui.lineageTypeSearch.val(that.searchNodeObj.selectedNode);
+                    that.ui.lineageTypeSearch.trigger("change.select2");
+                }
+            },
+            updateRelationshipDetails: function(options) {
+                var that = this,
+                    guid = options.guid,
+                    initialData = that.guidEntityMap[guid],
+                    typeName = initialData.typeName || guid,
+                    attributeDefs = that.g._nodes[guid] && that.g._nodes[guid].entityDef ? that.g._nodes[guid].entityDef.attributeDefs : null;
+                this.$("[data-id='typeName']").text(typeName);
+                this.entityModel = new VEntity({});
+                var config = {
+                    guid: 'guid',
+                    typeName: 'typeName',
+                    name: 'name',
+                    qualifiedName: 'qualifiedName',
+                    owner: 'owner',
+                    createTime: 'createTime',
+                    status: 'status',
+                    classificationNames: 'classifications',
+                    meanings: 'term'
+                };
+                var data = {};
+                _.each(config, function(valKey, key) {
+                    var val = initialData[key];
+                    if (_.isUndefined(val) && initialData.attributes[key]) {
+                        val = initialData.attributes[key];
+                    }
+                    if (val) {
+                        data[valKey] = val;
                     }
-                    var thead = '<thead><tr><th class="renderable">Type</th><th class="renderable">Details</th></thead>';
-                    var table = '<table style="word-wrap: break-word;" class="table table-hover ">' + thead + '<tbody>' + tbody + '</body></table>';
-                    return table;
+                });
+                this.ui.nodeDetailTable.html(CommonViewFunction.propertyTable({
+                    "scope": this,
+                    "valueObject": data,
+                    "attributeDefs": attributeDefs,
+                    "sortBy": false
+                }));
+            },
+            onClickSaveSvg: function(e, a) {
+                var that = this;
+                var loaderTargetDiv = $(e.currentTarget).find('>i');
 
+                if (loaderTargetDiv.hasClass('fa-refresh')) {
+                    Utils.notifyWarn({
+                        content: "Please wait while the lineage gets downloaded"
+                    });
+                    return false; // return if the lineage is not loaded.
+                }
+
+
+                that.toggleLoader(loaderTargetDiv);
+                Utils.notifyInfo({
+                    content: "Lineage will be downloaded in a moment."
+                });
+                setTimeout(function() {
+                    var svg = that.$('svg')[0],
+                        svgClone = svg.cloneNode(true),
+                        scaleFactor = 1,
+                        svgWidth = that.$('svg').width(),
+                        svgHeight = that.$('svg').height();
+                    if (platform.name === "Firefox") {
+                        svgClone.setAttribute('width', svgWidth);
+                        svgClone.setAttribute('height', svgHeight);
+                    }
+                    $('.hidden-svg').html(svgClone);
+                    $(svgClone).find('>g').attr("transform", "scale(" + scaleFactor + ")");
+                    var canvasOffset = { x: 150, y: 150 },
+                        setWidth = (svgClone.getBBox().width + (canvasOffset.x)),
+                        setHeight = (svgClone.getBBox().height + (canvasOffset.y)),
+                        xAxis = svgClone.getBBox().x,
+                        yAxis = svgClone.getBBox().y;
+                    svgClone.attributes.viewBox.value = xAxis + "," + yAxis + "," + setWidth + "," + setHeight;
+
+                    var createCanvas = document.createElement('canvas');
+                    createCanvas.id = "canvas";
+                    createCanvas.style.display = 'none';
+
+                    var body = $('body').append(createCanvas),
+                        canvas = $('canvas')[0];
+                    canvas.width = (svgClone.getBBox().width * scaleFactor) + canvasOffset.x;
+                    canvas.height = (svgClone.getBBox().height * scaleFactor) + canvasOffset.y;
+
+                    var ctx = canvas.getContext('2d'),
+                        data = (new XMLSerializer()).serializeToString(svgClone),
+                        DOMURL = window.URL || window.webkitURL || window;
+
+                    ctx.fillStyle = "#FFFFFF";
+                    ctx.fillRect(0, 0, canvas.width, canvas.height);
+                    ctx.strokeRect(0, 0, canvas.width, canvas.height);
+                    ctx.restore();
+
+                    var img = new Image(canvas.width, canvas.height);
+                    var svgBlob = new Blob([data], { type: 'image/svg+xml;base64' });
+                    if (platform.name === "Safari") {
+                        svgBlob = new Blob([data], { type: 'image/svg+xml' });
+                    }
+                    var url = DOMURL.createObjectURL(svgBlob);
+
+                    img.onload = function() {
+                        try {
+                            var a = document.createElement("a"),
+                                entityAttributes = that.entity && that.entity.attributes;
+                            a.download = ((entityAttributes && entityAttributes.qualifiedName) || "lineage_export") + ".png";
+                            document.body.appendChild(a);
+                            ctx.drawImage(img, 50, 50, canvas.width, canvas.height);
+                            canvas.toBlob(function(blob) {
+                                if (!blob) {
+                                    Utils.notifyError({
+                                        content: "There was an error in downloading Lineage!"
+                                    });
+                                    that.toggleLoader(loaderTargetDiv);
+                                    return;
+                                }
+                                a.href = DOMURL.createObjectURL(blob);
+                                if (blob.size > 10000000) {
+                                    Utils.notifyWarn({
+                                        content: "The Image size is huge, please open the image in a browser!"
+                                    });
+                                }
+                                a.click();
+                                that.toggleLoader(loaderTargetDiv);
+                                if (platform.name === 'Safari') {
+                                    LineageUtils.refreshGraphForSafari({
+                                        edgeEl: that.$('svg g.node')
+                                    });
+                                }
+                            }, 'image/png');
+                            $('.hidden-svg').html('');
+                            createCanvas.remove();
+
+                        } catch (err) {
+                            Utils.notifyError({
+                                content: "There was an error in downloading Lineage!"
+                            });
+                            that.toggleLoader(loaderTargetDiv);
+                        }
+
+                    };
+                    img.src = url;
+
+                }, 0)
+            },
+            toggleLoader: function(element) {
+                if ((element).hasClass('fa-camera')) {
+                    (element).removeClass('fa-camera').addClass("fa-spin-custom fa-refresh");
+                } else {
+                    (element).removeClass("fa-spin-custom fa-refresh").addClass('fa-camera');
+                }
+            },
+            onClickResetLineage: function() {
+                this.createGraph()
+            },
+            toggleDisableState: function(options) {
+                var el = options.el;
+                if (el && el.prop) {
+                    el.prop("disabled", !el.prop("disabled"));
                 }
-                listString += getElement(data);
-                this.ui.nodeEntityList.html(listString);
             }
         });
     return LineageLayoutView;
diff --git a/dashboardv2/public/js/views/graph/LineageUtils.js b/dashboardv2/public/js/views/graph/LineageUtils.js
new file mode 100644
index 0000000..d2da39a
--- /dev/null
+++ b/dashboardv2/public/js/views/graph/LineageUtils.js
@@ -0,0 +1,304 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+define(['require'], function(require) {
+    'use strict';
+    var LinegaeUtils = {};
+    LinegaeUtils.DragNode = function(options) {
+        var that = this,
+            g = options.g,
+            svg = options.svg,
+            guid = options.guid,
+            edgePathEl = options.edgeEl;
+        return {
+            init: function() {
+                var that = this;
+                //give IDs to each of the nodes so that they can be accessed
+                svg.selectAll("g.node rect")
+                    .attr("id", function(d) {
+                        return "node" + d;
+                    });
+                svg.selectAll("g.edgePath path")
+                    .attr("id", function(e) {
+                        return e.v + "-" + e.w;
+                    });
+                svg.selectAll("g.edgeLabel g")
+                    .attr("id", function(e) {
+                        return 'label_' + e.v + "-" + e.w;
+                    });
+
+                g.nodes().forEach(function(v) {
+                    var node = g.node(v);
+                    node.customId = "node" + v;
+                })
+                g.edges().forEach(function(e) {
+                    var edge = g.edge(e.v, e.w);
+                    edge.customId = e.v + "-" + e.w
+                });
+                var nodeDrag = d3.behavior.drag()
+                    .on("dragstart", this.dragstart)
+                    .on("drag", function(d) { that.dragmove(this, d) });
+
+                var edgeDrag = d3.behavior.drag()
+                    .on("dragstart", this.dragstart)
+                    .on('drag', function(d) {
+                        that.translateEdge(g.edge(d.v, d.w), d3.event.dx, d3.event.dy);
+                        $('#' + g.edge(d.v, d.w).customId).attr('d', that.calcPoints(d));
+                    });
+
+                nodeDrag.call(svg.selectAll("g.node"));
+                edgeDrag.call(svg.selectAll("g.edgePath"));
+            },
+            dragstart: function(d) {
+                d3.event.sourceEvent.stopPropagation();
+            },
+            dragmove: function(elem, d) {
+                var that = this,
+                    node = d3.select(elem),
+                    selectedNode = g.node(d),
+                    prevX = selectedNode.x,
+                    prevY = selectedNode.y;
+
+                selectedNode.x += d3.event.dx;
+                selectedNode.y += d3.event.dy;
+                node.attr('transform', 'translate(' + selectedNode.x + ',' + selectedNode.y + ')');
+
+                var dx = selectedNode.x - prevX,
+                    dy = selectedNode.y - prevY;
+
+                g.edges().forEach(function(e) {
+                    if (e.v == d || e.w == d) {
+                        var edge = g.edge(e.v, e.w);
+                        that.translateEdge(g.edge(e.v, e.w), dx, dy);
+                        $('#' + edge.customId).attr('d', that.calcPoints(e));
+                        var label = $('#label_' + edge.customId);
+                        var xforms = label.attr('transform');
+                        if (xforms != "") {
+                            var parts = /translate\(\s*([^\s,)]+)[ ,]?([^\s,)]+)?/.exec(xforms),
+                                X = parseInt(parts[1]) + dx,
+                                Y = parseInt(parts[2]) + dy;
+                            if (isNaN(Y)) {
+                                Y = dy;
+                            }
+                            label.attr('transform', 'translate(' + X + ',' + Y + ')');
+                        }
+                    }
+                });
+                LinegaeUtils.refreshGraphForIE({ "edgeEl": edgePathEl })
+            },
+            translateEdge: function(e, dx, dy) {
+                e.points.forEach(function(p) {
+                    p.x = p.x + dx;
+                    p.y = p.y + dy;
+                });
+            },
+            calcPoints: function(e) {
+                var edge = g.edge(e.v, e.w),
+                    tail = g.node(e.v),
+                    head = g.node(e.w),
+                    points = edge.points.slice(1, edge.points.length - 1),
+                    afterslice = edge.points.slice(1, edge.points.length - 1);
+                points.unshift(this.intersectRect(tail, points[0]));
+                points.push(this.intersectRect(head, points[points.length - 1]));
+                return d3.svg.line()
+                    .x(function(d) {
+                        return d.x;
+                    })
+                    .y(function(d) {
+                        return d.y;
+                    })
+                    .interpolate("basis")
+                    (points);
+            },
+            intersectRect: function(node, point) {
+                var that = this,
+                    x = node.x,
+                    y = node.y,
+                    dx = point.x - x,
+                    dy = point.y - y,
+                    w = node.id == guid ? 24 : 21,
+                    h = node.id == guid ? 24 : 21,
+                    sx = 0,
+                    sy = 0;
+
+                if (Math.abs(dy) * w > Math.abs(dx) * h) {
+                    // Intersection is top or bottom of rect.
+                    if (dy < 0) {
+                        h = -h;
+                    }
+                    sx = dy === 0 ? 0 : h * dx / dy;
+                    sy = h;
+                } else {
+                    // Intersection is left or right of rect.
+                    if (dx < 0) {
+                        w = -w;
+                    }
+                    sx = w;
+                    sy = dx === 0 ? 0 : w * dy / dx;
+                }
+                return {
+                    x: x + sx,
+                    y: y + sy
+                };
+            },
+        }
+    }
+    LinegaeUtils.refreshGraphForSafari = function(options) {
+        var edgePathEl = options.edgeEl,
+            IEGraphRenderDone = 0;
+        edgePathEl.each(function(argument) {
+            var eleRef = this,
+                childNode = $(this).find('pattern');
+            setTimeout(function(argument) {
+                $(eleRef).find('defs').append(childNode);
+            }, 500);
+        });
+    }
+    LinegaeUtils.refreshGraphForIE = function(options) {
+        var edgePathEl = options.edgeEl,
+            IEGraphRenderDone = 0;
+        edgePathEl.each(function(argument) {
+            var childNode = $(this).find('marker');
+            $(this).find('marker').remove();
+            var eleRef = this;
+            ++IEGraphRenderDone;
+            setTimeout(function(argument) {
+                $(eleRef).find('defs').append(childNode);
+                --IEGraphRenderDone;
+                if (IEGraphRenderDone === 0) {
+                    this.$('.fontLoader').hide();
+                    this.$('svg').fadeTo(1000, 1)
+                }
+            }, 1000);
+        });
+    }
+    LinegaeUtils.centerNode = function(options) {
+        var nodeID = options.guid,
+            svg = options.svg,
+            g = options.g,
+            afterCenterZoomed = options.afterCenterZoomed,
+            zoom = d3.behavior.zoom(),
+            svgGroup = svg.find("g"),
+            edgePathEl = options.edgeEl,
+            zoomBind = function() {
+                svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+            },
+            selectedNode = $(svg).find("g.nodes").find('>g#' + nodeID);
+        return {
+            init: function() {
+                if (selectedNode.length > 0) {
+                    selectedNode = selectedNode;
+                    var matrix = selectedNode.attr('transform').replace(/[^0-9\-.,]/g, '').split(',');
+                    if (platform.name === "IE" || platform.name === "Microsoft Edge") {
+                        var matrix = selectedNode.attr('transform').replace(/[a-z\()]/g, '').split(' ');
+                    }
+                    var x = matrix[0],
+                        y = matrix[1];
+                } else {
+                    selectedNode = $(svg).find("g.nodes").find('g').eq(1);
+                    var x = g.graph().width / 2,
+                        y = g.graph().height / 2;
+
+                }
+                var viewerWidth = $(svg).width(),
+                    viewerHeight = $(svg).height(),
+                    gBBox = d3.select('g').node().getBBox(),
+                    zoomListener = zoom.scaleExtent([0.01, 50]).on("zoom", zoomBind),
+                    scale = 1.2,
+                    xa = -((x * scale) - (viewerWidth / 2)),
+                    ya = -((y * scale) - (viewerHeight / 2));
+
+                zoom.translate([xa, ya]);
+                d3.select('g').transition()
+                    .duration(350)
+                    .attr("transform", "translate(" + xa + "," + ya + ")scale(" + scale + ")");
+                zoomListener.scale(scale);
+                zoomListener.translate([xa, ya]);
+                zoom.scale(scale);
+                afterCenterZoomed({ newScale: scale, newTranslate: [xa, ya] });
+                LinegaeUtils.refreshGraphForIE({ "edgeEl": edgePathEl })
+            }
+        }
+    }
+    LinegaeUtils.onHoverFade = function(options) {
+        var opacity = options.opacity,
+            d = options.selectedNode,
+            nodesToHighlight = options.highlight,
+            svg = options.svg,
+            isConnected = function(a, b, o) {
+                if (a === o || (b && b.length && b.indexOf(o) != -1)) {
+                    return true;
+                }
+            },
+            node = svg.selectAll('.node'),
+            path = svg.selectAll('.edgePath');
+        return {
+            init: function() {
+                node.classed("hover-active", function(selectedNode, i, nodes) {
+                    if (isConnected(d, nodesToHighlight, selectedNode)) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                });
+                path.classed('hover-active-node', function(c) {
+                    var _thisOpacity = c.v === d || c.w === d ? 1 : 0;
+                    if (_thisOpacity) {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                });
+
+            }
+        }
+
+    }
+    LinegaeUtils.base64Encode = function(options) {
+        var str = options.data,
+            CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+            out = "",
+            i = 0,
+            len = str.length,
+            c1, c2, c3;
+        while (i < len) {
+            c1 = str.charCodeAt(i++) & 0xff;
+            if (i == len) {
+                out += CHARS.charAt(c1 >> 2);
+                out += CHARS.charAt((c1 & 0x3) << 4);
+                out += "==";
+                break;
+            }
+            c2 = str.charCodeAt(i++);
+            if (i == len) {
+                out += CHARS.charAt(c1 >> 2);
+                out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
+                out += CHARS.charAt((c2 & 0xF) << 2);
+                out += "=";
+                break;
+            }
+            c3 = str.charCodeAt(i++);
+            out += CHARS.charAt(c1 >> 2);
+            out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
+            out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
+            out += CHARS.charAt(c3 & 0x3F);
+        }
+        return out;
+    }
+    return LinegaeUtils;
+});
\ No newline at end of file