You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by sa...@apache.org on 2019/02/27 20:55:28 UTC

[atlas] branch branch-1.0 updated: ATLAS-3059: UI : Lineage data structure change to support hide deleted and hide process entities to gather

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

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


The following commit(s) were added to refs/heads/branch-1.0 by this push:
     new b21d218  ATLAS-3059: UI : Lineage data structure change to support hide deleted and hide process entities to gather
b21d218 is described below

commit b21d2185cde6ce26ec01d1246c1d3fc5c7cefbd6
Author: kevalbhatt <kb...@apache.org>
AuthorDate: Wed Feb 27 12:54:42 2019 -0800

    ATLAS-3059: UI : Lineage data structure change to support hide deleted and hide process entities to gather
    
    Signed-off-by: Sarath Subramanian <ss...@hortonworks.com>
    (cherry picked from commit 1cb155a2548f7f415132d229043f9f6bdce755c2)
---
 dashboardv2/public/css/scss/graph.scss             |  24 +-
 dashboardv2/public/css/scss/relationship.scss      |   4 +-
 .../js/templates/graph/LineageLayoutView_tmpl.html |  39 +-
 .../public/js/views/graph/LineageLayoutView.js     | 517 +++++++++++++--------
 4 files changed, 385 insertions(+), 199 deletions(-)

diff --git a/dashboardv2/public/css/scss/graph.scss b/dashboardv2/public/css/scss/graph.scss
index 4a9fd57..3c4be1e 100644
--- a/dashboardv2/public/css/scss/graph.scss
+++ b/dashboardv2/public/css/scss/graph.scss
@@ -34,6 +34,8 @@
         font-family: $font_1;
     }
 
+    transition: opacity 0.3s linear;
+
     rect {
         stroke: $color_mountain_mist_approx;
         fill: $white;
@@ -279,8 +281,7 @@ g.type-TK>rect {
     .zoom-button-group {}
 }
 
-.lineage-fltr-panel,
-.lineage-search-panel {
+.box-panel {
     position: absolute;
     top: 45px;
     border: 1px solid #ccc;
@@ -417,7 +418,8 @@ g.type-TK>rect {
 }
 
 .show-filter-panel,
-.show-search-panel {
+.show-search-panel,
+.show-box-panel {
     right: 0px !important;
 }
 
@@ -501,4 +503,20 @@ span#zoom_in {
 
 .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;
+    }
 }
\ No newline at end of file
diff --git a/dashboardv2/public/css/scss/relationship.scss b/dashboardv2/public/css/scss/relationship.scss
index e41fe58..c1112c5 100644
--- a/dashboardv2/public/css/scss/relationship.scss
+++ b/dashboardv2/public/css/scss/relationship.scss
@@ -16,11 +16,13 @@
  * limitations under the License.
  */
 
-.relationship-box {
+.relationship-box,
+.lineage-box {
     position: absolute;
     height: 100%;
     width: 100%;
     overflow: hidden;
+
     .relatioship-link {
         fill: none;
         stroke-width: 1.5px;
diff --git a/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html b/dashboardv2/public/js/templates/graph/LineageLayoutView_tmpl.html
index 3adc8ad..c27ff8c 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" style="margin: 7px" class="btn btn-action btn-sm fltr-togler"><i class="fa fa-close"></i></span>
         </div>
         <div class="body">
             <div class="hideProcessContainer form-group text-left col-sm-12">
@@ -46,10 +46,10 @@
             </div>
         </div>
     </div>
-    <div class="lineage-search-panel">
+    <div class="box-panel search-box">
         <div class="header clearfix">
             <h4>Search</h4>
-            <span data-id="search-togler" style="margin: 7px" class="btn btn-action btn-sm fltr-togler"><i class="fa fa-close"></i></span>
+            <span data-id="box-close" style="margin: 7px" class="btn btn-action btn-sm fltr-togler"><i class="fa fa-close"></i></span>
         </div>
         <div class="body">
             <div class="col-sm-12 no-padding">
@@ -64,12 +64,39 @@
             </div>
         </div>
     </div>
+    <div class="box-panel setting-box">
+        <div class="header clearfix">
+            <h4>Settings</h4>
+            <span data-id="box-close" style="margin: 7px" class="btn btn-action btn-sm fltr-togler"><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 type="button" data-id="setting-toggler" class="btn btn-action btn-gray btn-sm"><i class="fa fa-gear"></i></button>
+        </div>
+        <div>
+            <button type="button" data-id="filter-toggler" class="btn btn-action btn-gray btn-sm"><i class="fa fa-filter"></i></button>
         </div>
         <div>
-            <button type="button" data-id="search-togler" class="btn btn-action btn-gray btn-sm"><i class="fa fa-search"></i></button>
+            <button type="button" data-id="search-toggler" class="btn btn-action btn-gray btn-sm"><i class="fa fa-search"></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>
diff --git a/dashboardv2/public/js/views/graph/LineageLayoutView.js b/dashboardv2/public/js/views/graph/LineageLayoutView.js
index 5a7262b..e98a6fa 100644
--- a/dashboardv2/public/js/views/graph/LineageLayoutView.js
+++ b/dashboardv2/public/js/views/graph/LineageLayoutView.js
@@ -49,15 +49,20 @@ define(['require',
                 checkHideProcess: "[data-id='checkHideProcess']",
                 checkDeletedEntity: "[data-id='checkDeletedEntity']",
                 selectDepth: 'select[data-id="selectDepth"]',
-                fltrTogler: '[data-id="fltr-togler"]',
-                lineageFilterPanel: '.lineage-fltr-panel',
+                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"]',
-                searchTogler: '[data-id="search-togler"]',
-                lineageSearchPanel: '.lineage-search-panel',
+                filterBox: '.filter-box',
+                searchBox: '.search-box',
+                settingBox: '.setting-box',
                 lineageTypeSearch: '[data-id="typeSearch"]',
                 lineageDetailClose: '[data-id="close"]',
                 searchNode: '[data-id="searchNode"]',
-                nodeEntityList: '[data-id="entityList"]'
+                nodeEntityList: '[data-id="entityList"]',
+                showOnlyHoverPath: '[data-id="showOnlyHoverPath"]',
+                showTooltip: '[data-id="showTooltip"]'
             },
             templateHelpers: function() {
                 return {
@@ -71,9 +76,11 @@ define(['require',
                 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.filterToggler] = 'onClickFilterToggler';
+                events["click " + this.ui.boxClose] = 'toggleBoxPanel';
+                events["click " + this.ui.settingToggler] = 'onClickSettingToggler';
                 events["click " + this.ui.lineageFullscreenToggler] = 'onClickLineageFullscreenToggler';
-                events["click " + this.ui.searchTogler] = 'onClickSearchTogler';
+                events["click " + this.ui.searchToggler] = 'onClickSearchToggler';
                 events["click " + this.ui.lineageDetailClose] = function() {
                     this.toggleLineageInfomationSlider({ close: true });
                 };
@@ -119,7 +126,6 @@ define(['require',
                         return {};
                     });
             },
-
             onRender: function() {
                 var that = this;
                 this.fetchGraphData();
@@ -158,32 +164,30 @@ define(['require',
             },
             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);
-            },
-            onClickFiltrTogler: function() {
-                var lineageFilterPanel = this.ui.lineageFilterPanel;
-                var lineageSearchPanel = this.ui.lineageSearchPanel;
-                $(lineageFilterPanel).toggleClass("show-filter-panel");
-                if (lineageSearchPanel.hasClass('show-search-panel')) {
-                    $(this.ui.lineageSearchPanel).toggleClass("show-search-panel")
-                }
+                this.generateData({ "relationshipMap": this.relationshipMap, "guidEntityMap": this.guidEntityMap });
             },
-            onClickSearchTogler: function() {
-                var lineageSearchPanel = this.ui.lineageSearchPanel;
-                var lineageFilterPanel = this.ui.lineageFilterPanel;
-                $(lineageSearchPanel).toggleClass("show-search-panel");
-                if (lineageFilterPanel.hasClass('show-filter-panel')) {
-                    $(this.ui.lineageFilterPanel).toggleClass("show-filter-panel");
-
+            toggleBoxPanel: function(el) {
+                this.$el.find('.show-box-panel').removeClass('show-box-panel');
+                if (el && el.addClass) {
+                    el.addClass('show-box-panel');
                 }
             },
+            onClickFilterToggler: function() {
+                this.toggleBoxPanel(this.ui.filterBox);
+            },
+            onClickSettingToggler: function() {
+                this.toggleBoxPanel(this.ui.settingBox);
+            },
+            onClickSearchToggler: function() {
+                this.toggleBoxPanel(this.ui.searchBox);
+            },
             onSelectDepthChange: function(e, options) {
                 this.initializeGraph();
                 this.filterObj.depthCount = e.currentTarget.value;
@@ -193,7 +197,7 @@ define(['require',
             fetchGraphData: function(options) {
                 var that = this,
                     queryParam = options && options.queryParam || {};
-                this.fromToObj = {};
+                this.fromToNodeData = {};
                 this.$('.fontLoader').show();
                 this.$('svg>g').hide();
                 this.collection.getLineage(this.guid, {
@@ -201,8 +205,13 @@ define(['require',
                     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);
+                            if (that.lineageData) {
+                                that.renderLineageTypeSearch();
+                            }
+                            that.generateData({ "relationshipMap": that.relationshipMap, "guidEntityMap": that.guidEntityMap });
                         } else {
                             that.noLineage();
                             that.hideCheckForProcess();
@@ -221,7 +230,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();
@@ -230,168 +238,227 @@ 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.toJSON(), collection: this.entityDefCollection })
+            },
+            getEntityDef: function(typeName) {
+                var entityDef = null;
+                if (typeName) {
+                    entityDef = this.entityDefCollection.fullCollection.find({ name: typeName });
                 }
-
-                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.get("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 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;
+                                } else {
+                                    newRelationship.push(guid);
                                 }
-                                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.fromToNodeData[this.guid]) {
+                    this.fromToNodeData[this.guid]['isLineage'] = false;
+                    this.findImpactNodeAndUpdateData({ "relationshipMap": filterRelationshipMap, "guid": this.guid, "getStyleObjStr": getStyleObjStr });
                 }
                 if (this.asyncFetchCounter == 0) {
                     this.createGraph();
                 }
-                if (this.lineageData) {
-                    this.renderLineageTypeSearch();
-                    this.lineageTypeSearch()
-                }
             },
-            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);
-                        }
-                    });
+                            that.g.setEdge(fromNodeGuid, toNodeGuid, {
+                                "arrowhead": 'arrowPoint',
+                                "lineInterpolate": 'basis',
+                                "style": getStyleObjStr(styleObj),
+                                'styleObj': styleObj
+                            });
+                            that.findImpactNodeAndUpdateData({
+                                "relationshipMap": relationshipMap,
+                                "guid": toNodeGuid,
+                                "getStyleObjStr": getStyleObjStr
+                            });
+                        });
+                    }
                 }
             },
             toggleInformationSlider: function(options) {
@@ -404,12 +471,22 @@ define(['require',
             },
             centerNode: function(nodeID) {
                 var zoom = function() {
-                        svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
-                    },
-                    matrix = this.$('svg').find("g.nodes").find('>g#' + nodeID).attr('transform').replace(/[^0-9\-.,]/g, '').split(','),
-                    x = matrix[0],
-                    y = matrix[1],
-                    viewerWidth = this.$('svg').width(),
+                    svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
+                };
+                var selectedNode = this.$('svg').find("g.nodes").find('>g#' + nodeID);
+
+                if (selectedNode.length > 0) {
+                    selectedNode = selectedNode;
+                    var matrix = selectedNode.attr('transform').replace(/[^0-9\-.,]/g, '').split(','),
+                        x = matrix[0],
+                        y = matrix[1];
+                } else {
+                    selectedNode = this.$('svg').find("g.nodes").find('g').eq(1);
+                    var x = this.g.graph().width / 2,
+                        y = this.g.graph().height / 2;
+
+                }
+                var viewerWidth = this.$('svg').width(),
                     viewerHeight = this.$('svg').height(),
                     gBBox = d3.select('g').node().getBBox(),
                     zoomListener = d3.behavior.zoom().scaleExtent([0.01, 50]).on("zoom", zoom),
@@ -577,8 +654,39 @@ define(['require',
                 svg.on("dblclick.zoom", null)
                 // .on("wheel.zoom", null);
                 //change text postion 
+
+                function isConnected(a, b, o) {
+                    //console.log(a, b, o);
+                    if (a === o || (b && b.length && b.indexOf(o) != -1)) {
+                        return true;
+                    }
+                }
+
+                function fade(opacity, d, nodesToHighlight) {
+                    var node = svg.selectAll('.node');
+                    var path = svg.selectAll('.edgePath');
+                    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;
+                        }
+
+                    });
+
+                }
+                //Highlight on click
                 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;
@@ -604,38 +712,68 @@ 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);
+                        fade(0.3, d, nodesToHighlight);
                     })
-                    .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) {
+                        }, 400);
+                        if (!that.ui.showOnlyHoverPath.prop('checked')) {
+                            return;
+                        }
+                        that.$('svg').removeClass('hover');
+                        fade(1, d);
+                    })
+                    .on('click', function(d) {
                         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.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 });
+                                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;
@@ -692,8 +830,9 @@ define(['require',
                     });
                 }
                 that.ui.lineageTypeSearch.html(typeStr);
+                this.initilizelineageTypeSearch()
             },
-            lineageTypeSearch: function() {
+            initilizelineageTypeSearch: function() {
                 var that = this;
                 that.ui.lineageTypeSearch.select2({
                     closeOnSelect: true,