ATLAS-3911: UI: Type system managment
This commit is contained in:
parent
74229d8704
commit
b8956dfd00
|
|
@ -24,4 +24,6 @@ target/
|
|||
*.log
|
||||
*.tgz
|
||||
node/
|
||||
.npmrc
|
||||
dist/
|
||||
!public/js/external_lib/atlas-lineage/dist
|
||||
|
|
@ -94,7 +94,7 @@ module.exports = function(grunt) {
|
|||
'backgrid-sizeable-columns.js': { 'backgrid-sizeable-columns': 'backgrid-sizeable-columns/js' },
|
||||
'Backgrid.ColumnManager.js': { 'backgrid-columnmanager/src': 'backgrid-columnmanager/js' },
|
||||
'jquery-asBreadcrumbs.min.js': { 'jquery-asBreadcrumbs/dist': 'jquery-asBreadcrumbs/js' },
|
||||
'd3.min.js': { 'd3': 'd3' },
|
||||
'd3.min.js': { 'd3/dist': 'd3' },
|
||||
'index.js': { 'd3-tip': 'd3/' },
|
||||
'dagre-d3.min.js': { 'dagre-d3/dist': 'dagre-d3' },
|
||||
'select2.full.min.js': { 'select2/dist/js': 'select2' },
|
||||
|
|
@ -218,7 +218,7 @@ module.exports = function(grunt) {
|
|||
build: {
|
||||
expand: true,
|
||||
cwd: modulesPath,
|
||||
src: ['**', '!**/scss/**', "!index.html.tpl"],
|
||||
src: ['**', '!**/scss/**', "!**/atlas-lineage/**", "**/atlas-lineage/dist/**", "!index.html.tpl"],
|
||||
dest: distPath
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@
|
|||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
|
||||
"integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
|
||||
"version": "6.12.4",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
|
||||
"integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
|
|
@ -179,9 +179,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
|
||||
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==",
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
|
||||
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-runtime": {
|
||||
|
|
@ -617,9 +617,42 @@
|
|||
"integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU="
|
||||
},
|
||||
"d3": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz",
|
||||
"integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g="
|
||||
"version": "5.14.2",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-5.14.2.tgz",
|
||||
"integrity": "sha512-Ccipa9XrYW5N0QkP6u0Qb8kU6WekIXBiDenmZm1zLvuq/9pBBhRCJLCICEOsH5Og4B0Xw02bhqGkK5VN/oPH0w==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-axis": "1",
|
||||
"d3-brush": "1",
|
||||
"d3-chord": "1",
|
||||
"d3-collection": "1",
|
||||
"d3-color": "1",
|
||||
"d3-contour": "1",
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
"d3-dsv": "1",
|
||||
"d3-ease": "1",
|
||||
"d3-fetch": "1",
|
||||
"d3-force": "1",
|
||||
"d3-format": "1",
|
||||
"d3-geo": "1",
|
||||
"d3-hierarchy": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-path": "1",
|
||||
"d3-polygon": "1",
|
||||
"d3-quadtree": "1",
|
||||
"d3-random": "1",
|
||||
"d3-scale": "2",
|
||||
"d3-scale-chromatic": "1",
|
||||
"d3-selection": "1",
|
||||
"d3-shape": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2",
|
||||
"d3-timer": "1",
|
||||
"d3-transition": "1",
|
||||
"d3-voronoi": "1",
|
||||
"d3-zoom": "1"
|
||||
}
|
||||
},
|
||||
"d3-array": {
|
||||
"version": "1.2.4",
|
||||
|
|
@ -632,9 +665,9 @@
|
|||
"integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
|
||||
},
|
||||
"d3-brush": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.5.tgz",
|
||||
"integrity": "sha512-rEaJ5gHlgLxXugWjIkolTA0OyMvw8UWU1imYXy1v642XyyswmI1ybKOv05Ft+ewq+TFmdliD3VuK0pRp1VT/5A==",
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz",
|
||||
"integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==",
|
||||
"requires": {
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
|
|
@ -658,9 +691,9 @@
|
|||
"integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
|
||||
},
|
||||
"d3-color": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz",
|
||||
"integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg=="
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
|
||||
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
|
||||
},
|
||||
"d3-contour": {
|
||||
"version": "1.3.2",
|
||||
|
|
@ -695,14 +728,14 @@
|
|||
}
|
||||
},
|
||||
"d3-ease": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.6.tgz",
|
||||
"integrity": "sha512-SZ/lVU7LRXafqp7XtIcBdxnWl8yyLpgOmzAk0mWBI9gXNzLDx5ybZgnRbH9dN/yY5tzVBqCQ9avltSnqVwessQ=="
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz",
|
||||
"integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ=="
|
||||
},
|
||||
"d3-fetch": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.2.tgz",
|
||||
"integrity": "sha512-S2loaQCV/ZeyTyIF2oP8D1K9Z4QizUzW7cWeAOAS4U88qOt3Ucf6GsmgthuYSdyB2HyEm4CeGvkQxWsmInsIVA==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz",
|
||||
"integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==",
|
||||
"requires": {
|
||||
"d3-dsv": "1"
|
||||
}
|
||||
|
|
@ -719,14 +752,14 @@
|
|||
}
|
||||
},
|
||||
"d3-format": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.4.tgz",
|
||||
"integrity": "sha512-TWks25e7t8/cqctxCmxpUuzZN11QxIA7YrMbram94zMQ0PXjE4LVIMe/f6a4+xxL8HQ3OsAFULOINQi1pE62Aw=="
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
|
||||
"integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
|
||||
},
|
||||
"d3-geo": {
|
||||
"version": "1.11.9",
|
||||
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.11.9.tgz",
|
||||
"integrity": "sha512-9edcH6J3s/Aa3KJITWqFJbyB/8q3mMlA9Fi7z6yy+FAYMnRaxmC7jBhUnsINxVWD14GmqX3DK8uk7nV6/Ekt4A==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz",
|
||||
"integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==",
|
||||
"requires": {
|
||||
"d3-array": "1"
|
||||
}
|
||||
|
|
@ -787,9 +820,9 @@
|
|||
}
|
||||
},
|
||||
"d3-selection": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.1.tgz",
|
||||
"integrity": "sha512-BTIbRjv/m5rcVTfBs4AMBLKs4x8XaaLkwm28KWu9S2vKNqXkXt2AH2Qf0sdPZHjFxcWg/YL53zcqAz+3g4/7PA=="
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
|
||||
"integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
|
||||
},
|
||||
"d3-shape": {
|
||||
"version": "1.3.7",
|
||||
|
|
@ -805,9 +838,9 @@
|
|||
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
|
||||
},
|
||||
"d3-time-format": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.2.3.tgz",
|
||||
"integrity": "sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
|
||||
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
|
||||
"requires": {
|
||||
"d3-time": "1"
|
||||
}
|
||||
|
|
@ -823,6 +856,13 @@
|
|||
"integrity": "sha1-5bRJGuiYP95kbqSQCP9UKgM8Ciw=",
|
||||
"requires": {
|
||||
"d3": "^3.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz",
|
||||
"integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g="
|
||||
}
|
||||
}
|
||||
},
|
||||
"d3-transition": {
|
||||
|
|
@ -873,46 +913,6 @@
|
|||
"dagre": "^0.8.5",
|
||||
"graphlib": "^2.1.8",
|
||||
"lodash": "^4.17.15"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": {
|
||||
"version": "5.15.1",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-5.15.1.tgz",
|
||||
"integrity": "sha512-Xu9gT6Lm0jH3wWJJSRomFwqnGGi3YAfWIfxNFl4++YVgYOjo3F8V2idAG3nJBgpZOkD0/RHPZX6F4k6tzgOvYw==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-axis": "1",
|
||||
"d3-brush": "1",
|
||||
"d3-chord": "1",
|
||||
"d3-collection": "1",
|
||||
"d3-color": "1",
|
||||
"d3-contour": "1",
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
"d3-dsv": "1",
|
||||
"d3-ease": "1",
|
||||
"d3-fetch": "1",
|
||||
"d3-force": "1",
|
||||
"d3-format": "1",
|
||||
"d3-geo": "1",
|
||||
"d3-hierarchy": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-path": "1",
|
||||
"d3-polygon": "1",
|
||||
"d3-quadtree": "1",
|
||||
"d3-random": "1",
|
||||
"d3-scale": "2",
|
||||
"d3-scale-chromatic": "1",
|
||||
"d3-selection": "1",
|
||||
"d3-shape": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2",
|
||||
"d3-timer": "1",
|
||||
"d3-transition": "1",
|
||||
"d3-voronoi": "1",
|
||||
"d3-zoom": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashdash": {
|
||||
|
|
@ -1105,9 +1105,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
|
||||
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
|
|
@ -1309,13 +1309,13 @@
|
|||
}
|
||||
},
|
||||
"globule": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz",
|
||||
"integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
|
||||
"integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "~7.1.1",
|
||||
"lodash": "~4.17.12",
|
||||
"lodash": "~4.17.10",
|
||||
"minimatch": "~3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
@ -1336,9 +1336,9 @@
|
|||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
|
||||
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
|
||||
"dev": true
|
||||
},
|
||||
"graceful-readlink": {
|
||||
|
|
@ -1693,12 +1693,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
|
||||
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
|
||||
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.5.5",
|
||||
"ajv": "^6.12.3",
|
||||
"har-schema": "^2.0.0"
|
||||
}
|
||||
},
|
||||
|
|
@ -1801,9 +1801,9 @@
|
|||
}
|
||||
},
|
||||
"http-parser-js": {
|
||||
"version": "0.4.10",
|
||||
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
|
||||
"integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=",
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz",
|
||||
"integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"http-signature": {
|
||||
|
|
@ -1979,9 +1979,9 @@
|
|||
"integrity": "sha1-DO7gsNLkkUOYGtEg1FjtVuqOGSQ="
|
||||
},
|
||||
"js-base64": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
|
||||
"integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==",
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
|
||||
"integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
|
|
@ -2094,9 +2094,9 @@
|
|||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
||||
},
|
||||
"longest": {
|
||||
"version": "1.0.1",
|
||||
|
|
@ -2205,18 +2205,18 @@
|
|||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.43.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
|
||||
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.26",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
|
||||
"integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mime-db": "1.43.0"
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
|
|
@ -2288,9 +2288,9 @@
|
|||
}
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
|
||||
"version": "2.14.1",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
|
||||
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
|
||||
"dev": true
|
||||
},
|
||||
"ncname": {
|
||||
|
|
@ -2696,9 +2696,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.9.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
|
||||
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==",
|
||||
"version": "6.9.4",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
|
||||
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"range-parser": {
|
||||
|
|
@ -2856,9 +2856,9 @@
|
|||
"integrity": "sha1-ExOHM2E/xEV7fhJH6Mt1HfeqVCk="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.0.tgz",
|
||||
"integrity": "sha512-LarL/PIKJvc09k1jaeT4kQb/8/7P+qV4qSnN2K80AES+OHdfZELAKVOBjxsvtToT/uLOfFbvYvKfZmV8cee7nA==",
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
|
||||
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.6"
|
||||
|
|
@ -2941,9 +2941,9 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"sass-graph": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
|
||||
"integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.6.tgz",
|
||||
"integrity": "sha512-MKuEYXFSGuRSi8FZ3A7imN1CeVn9Gpw0/SFJKdL1ejXJneI9a5rwlEZrKejhEFAA3O6yr3eIyl/WuvASvlT36g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.0.0",
|
||||
|
|
@ -2970,9 +2970,9 @@
|
|||
}
|
||||
},
|
||||
"yargs": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
|
||||
"integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz",
|
||||
"integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^3.0.0",
|
||||
|
|
@ -2987,7 +2987,7 @@
|
|||
"string-width": "^1.0.2",
|
||||
"which-module": "^1.0.0",
|
||||
"y18n": "^3.2.1",
|
||||
"yargs-parser": "^5.0.0"
|
||||
"yargs-parser": "5.0.0-security.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3134,9 +3134,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"spdx-correct": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
|
||||
"integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
|
||||
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"spdx-expression-parse": "^3.0.0",
|
||||
|
|
@ -3144,15 +3144,15 @@
|
|||
}
|
||||
},
|
||||
"spdx-exceptions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
|
||||
"integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
|
||||
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
|
||||
"dev": true
|
||||
},
|
||||
"spdx-expression-parse": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
|
||||
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
|
||||
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"spdx-exceptions": "^2.1.0",
|
||||
|
|
@ -3445,9 +3445,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
|
||||
"integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
|
|
@ -3499,20 +3499,20 @@
|
|||
}
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
|
||||
"integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==",
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||
"integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"http-parser-js": ">=0.4.0 <0.4.11",
|
||||
"http-parser-js": ">=0.5.1",
|
||||
"safe-buffer": ">=5.1.0",
|
||||
"websocket-extensions": ">=0.1.1"
|
||||
}
|
||||
},
|
||||
"websocket-extensions": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
|
||||
"integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
|
||||
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
||||
"dev": true
|
||||
},
|
||||
"which": {
|
||||
|
|
@ -3606,12 +3606,13 @@
|
|||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
|
||||
"integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
|
||||
"version": "5.0.0-security.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz",
|
||||
"integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^3.0.0"
|
||||
"camelcase": "^3.0.0",
|
||||
"object.assign": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"camelcase": {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
"backgrid-sizeable-columns": "0.1.1",
|
||||
"bootstrap": "3.3.7",
|
||||
"bootstrap-daterangepicker": "3.1.0",
|
||||
"d3": "3.5.17",
|
||||
"d3": "5.14.2",
|
||||
"d3-tip": "0.6.8",
|
||||
"dagre-d3": "0.6.4",
|
||||
"dropzone": "5.7.0",
|
||||
|
|
|
|||
|
|
@ -14,189 +14,14 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
/* graph.scss */
|
||||
|
||||
|
||||
/* .graph-bg svg {
|
||||
background-image: linear-gradient(to right, $black -10px, rgba(0, 0, 0, 0) 1px), linear-gradient($black -10px, $color_cararra_approx 1px);
|
||||
background-size: 10px 10px;
|
||||
position: relative;
|
||||
} */
|
||||
|
||||
.node {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 10px;
|
||||
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 {
|
||||
fill: $color_suva_gray_approx;
|
||||
|
||||
&.highlight {
|
||||
cursor: pointer;
|
||||
fill: $color_havelock_blue_approx;
|
||||
text-decoration: underline;
|
||||
|
||||
tspan {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
circle {
|
||||
-moz-transition: all 0.3s;
|
||||
-webkit-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
stroke-width: 1.5px;
|
||||
|
||||
&.node-detail-highlight {
|
||||
stroke: $color_havelock_blue_approx;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
&.nodeImage {
|
||||
&.green:hover {
|
||||
stroke: #ffb203;
|
||||
}
|
||||
|
||||
&.blue:hover {
|
||||
stroke: #4b91e2;
|
||||
}
|
||||
|
||||
&.currentNode {
|
||||
stroke: #fb4200;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
-moz-transform: scale(1.4);
|
||||
-webkit-transform: scale(1.4);
|
||||
transform: scale(1.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
circle {
|
||||
-moz-transform: scale(1.4);
|
||||
-webkit-transform: scale(1.4);
|
||||
transform: scale(1.4);
|
||||
|
||||
&.nodeImage {
|
||||
&.green {
|
||||
stroke: #ffb203;
|
||||
}
|
||||
|
||||
&.blue {
|
||||
stroke: #4b91e2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invisible {
|
||||
.node circle {
|
||||
transition: all 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.edgePath {
|
||||
.path {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {}
|
||||
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: $color_celeste_approx;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.d3-tip {
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
padding: 12px;
|
||||
background: $black_80;
|
||||
color: $white;
|
||||
z-index: 999;
|
||||
max-width: 300px; //Instead of the line below you could use @include border-radius($radius, $vertical-radius)
|
||||
border-radius: 2px;
|
||||
|
||||
.tip-inner-scroll {
|
||||
overflow: auto;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
/* Creates a small triangle extender for the tooltip */
|
||||
&:after {
|
||||
box-sizing: border-box;
|
||||
display: inline;
|
||||
font-size: 10px;
|
||||
width: 100%;
|
||||
line-height: 1;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* Nrthward tooltips */
|
||||
&.n:after {
|
||||
content: "\25BC";
|
||||
margin: -1px 0 0 0;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Eastward tooltips */
|
||||
&.e:after {
|
||||
content: "\25C0";
|
||||
margin: -4px 0 0 0;
|
||||
top: 50%;
|
||||
left: -8px;
|
||||
}
|
||||
|
||||
/* Southward tooltips */
|
||||
&.s:after {
|
||||
content: "\25B2";
|
||||
margin: 0 0 1px 0;
|
||||
top: -8px;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Westward tooltips */
|
||||
&.w:after {
|
||||
content: "\25B6";
|
||||
margin: -4px 0 0 -1px;
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
g.type-TK>rect {
|
||||
fill: $color_bright_turquoise_approx;
|
||||
}
|
||||
|
||||
|
||||
.graph-toolbar {
|
||||
background-color: $white;
|
||||
margin-bottom: 10px;
|
||||
|
|
@ -206,7 +31,7 @@ g.type-TK>rect {
|
|||
.legends {
|
||||
>i {
|
||||
>span {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-family: "Source Sans Pro";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -275,7 +100,6 @@ g.type-TK>rect {
|
|||
text-align: left;
|
||||
|
||||
&.deleted-relation {
|
||||
|
||||
.deleteBtn {
|
||||
padding: 2px 8px !important;
|
||||
margin: 5px 5px !important;
|
||||
|
|
@ -283,7 +107,6 @@ g.type-TK>rect {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.header {
|
||||
background: $color_havelock_blue_approx;
|
||||
color: white;
|
||||
|
|
@ -327,7 +150,7 @@ g.type-TK>rect {
|
|||
background: white;
|
||||
|
||||
&[disabled] {
|
||||
opacity: .3;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
|
@ -337,8 +160,6 @@ g.type-TK>rect {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
span#zoom_in {
|
||||
border-bottom: 1px solid #625555;
|
||||
}
|
||||
|
|
@ -364,7 +185,7 @@ span#zoom_in {
|
|||
}
|
||||
|
||||
.active.fullscreen-mode {
|
||||
position: fixed;
|
||||
position: fixed !important;
|
||||
height: 100% !important;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
|
@ -374,6 +195,11 @@ span#zoom_in {
|
|||
padding: 0 !important;
|
||||
z-index: 9999;
|
||||
overflow: hidden !important;
|
||||
background: white;
|
||||
|
||||
.systemTypeTree {
|
||||
height: 100vh !important;
|
||||
}
|
||||
|
||||
.resizeGraph {
|
||||
position: fixed;
|
||||
|
|
@ -393,40 +219,6 @@ span#zoom_in {
|
|||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
|
@ -437,12 +229,7 @@ span#zoom_in {
|
|||
}
|
||||
}
|
||||
|
||||
.hidden-svg {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#tab-relationship {
|
||||
|
||||
.entity-status {
|
||||
&.active {
|
||||
color: $color_jungle_green_approx;
|
||||
|
|
@ -451,12 +238,10 @@ span#zoom_in {
|
|||
&.deleted {
|
||||
color: $delete_link;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.entity-list {
|
||||
list-style-position: inside;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -468,4 +253,17 @@ span#zoom_in {
|
|||
to {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.mini-map-type-system {
|
||||
background: white;
|
||||
width: 200px;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
|
||||
&>svg {
|
||||
box-shadow: 0px 0px 3px 1px #80808080;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -69,6 +69,7 @@
|
|||
<link href="js/libs/pretty-checkbox/css/pretty-checkbox.min.css?bust=<%- bust %>" rel="stylesheet">
|
||||
<link href="js/libs/dropzone/css/dropzone.css?bust=<%- bust %>" rel="stylesheet">
|
||||
<link href="js/libs/jstree/css/default/default-theme.min.css?bust=<%- bust %>" rel="stylesheet">
|
||||
<link href="js/external_lib/atlas-lineage/dist/styles.css?bust=<%- bust %>" rel="stylesheet">
|
||||
<link href="css/style.css?bust=<%- bust %>" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,204 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed 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.
|
||||
|
||||
|
||||
=======================================================================
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
.node{cursor:pointer}.node text{font-size:10px;font-family:sans-serif}.node rect{stroke:#999;fill:#fff;stroke-width:1.5px}.node rect.serach-rect{stroke:#37bb9b;fill:transparent;stroke-width:2.5px}.node .label{fill:#868686}.node .label.highlight{cursor:pointer;fill:#4a90e2;text-decoration:underline}.node .label.highlight tspan{font-weight:400}.node circle{-moz-transition:all 0.3s;-webkit-transition:all 0.3s;transition:all 0.3s;stroke-width:1.5px}.node circle.node-detail-highlight{stroke:#4a90e2;stroke-width:2px}.node circle.nodeImage.green:hover{stroke:#ffb203}.node circle.nodeImage.blue:hover{stroke:#4b91e2}.node circle.nodeImage.currentNode{stroke:#fb4200}.node circle.nodeImage:hover{-moz-transform:scale(1.4);-webkit-transform:scale(1.4);transform:scale(1.4)}.node.active circle{-moz-transform:scale(1.4);-webkit-transform:scale(1.4);transform:scale(1.4)}.node.active circle.nodeImage.green{stroke:#ffb203}.node.active circle.nodeImage.blue{stroke:#4b91e2}.legends>span{margin-right:8px;font-family:Source Sans Pro}svg.hover g.node{opacity:0.1 !important}svg.hover g.edgePath{opacity:0 !important}svg.hover g.node.hover-active-node,svg.hover g.edgePath.hover-active-path{opacity:1 !important}.invisible .node circle{transition:all 0s}.edgePath .path{cursor:pointer}.link{fill:none;stroke:#ccc;stroke-width:1.5px}.text-center{text-align:center}.d3-tip{line-height:1;font-weight:bold;padding:12px;background:rgba(0,0,0,0.8);color:#fff;z-index:999;max-width:300px;border-radius:2px}.d3-tip .tip-inner-scroll{overflow:auto;max-height:300px}.d3-tip .tip-inner-scroll h5{margin:7px 0px}.d3-tip:after{box-sizing:border-box;display:inline;font-size:10px;width:100%;line-height:1;color:rgba(0,0,0,0.8);position:absolute}.d3-tip.n:after{content:"\25BC";margin:-1px 0 0 0;top:100%;left:0;text-align:center}.d3-tip.e:after{content:"\25C0";margin:-4px 0 0 0;top:50%;left:-8px}.d3-tip.s:after{content:"\25B2";margin:0 0 1px 0;top:-8px;left:0;text-align:center}.d3-tip.w:after{content:"\25B6";margin:-4px 0 0 -1px;top:50%;left:100%}g.type-TK>rect{fill:#00ffd0}.fullscreen-mode{position:fixed;height:100% !important;top:0;bottom:0;left:0;width:100%;right:0;padding:0 !important;z-index:9999;overflow:hidden !important}.fullscreen-mode .resizeGraph{position:fixed;height:100% !important}.fullscreen-mode .resizeGraph .ui-resizable-handle{display:none}.fullscreen-mode .lineage-box{padding:10px !important}.fullscreen-mode .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}.hidden-svg{visibility:hidden}@-webkit-keyframes blink{from{opacity:0.2}to{opacity:0.5}}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "atlas-lineage-module",
|
||||
"version": "1.0.0",
|
||||
"description": "The module will help to render the lineage graph with the help dagre-d3,d3 js lib",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"start": "NODE_ENV=development webpack --watch",
|
||||
"build": "webpack"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/apache/atlas.git"
|
||||
},
|
||||
"keywords": [
|
||||
"lineage",
|
||||
"dagre-d3",
|
||||
"d3"
|
||||
],
|
||||
"author": "kevalbhatt",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/apache/atlas/issues"
|
||||
},
|
||||
"homepage": "https://github.com/apache/atlas#readme",
|
||||
"dependencies": {
|
||||
"d3-tip": "^0.9.1",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"platform": "^1.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.6",
|
||||
"@babel/preset-env": "^7.9.6",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"css-loader": "^3.5.3",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"path": "^0.12.7",
|
||||
"sass": "^1.26.5",
|
||||
"sass-loader": "^8.0.2",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export default {
|
||||
entityStateReadOnly: {
|
||||
ACTIVE: false,
|
||||
DELETED: true,
|
||||
STATUS_ACTIVE: false,
|
||||
STATUS_DELETED: true
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,361 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
import Enums from "../Enums";
|
||||
import { curveBasis } from "d3-shape";
|
||||
|
||||
const DataUtils = {
|
||||
/**
|
||||
* [getBaseUrl description]
|
||||
* @param {[type]} url [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getBaseUrl: function(url) {
|
||||
return url.replace(/\/[\w-]+.(jsp|html)|\/+$/gi, "");
|
||||
},
|
||||
/**
|
||||
* [getEntityIconPath description]
|
||||
* @param {[type]} options.entityData [description]
|
||||
* @param {Object} options.errorUrl } [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getEntityIconPath: function({ entityData, errorUrl } = {}) {
|
||||
var serviceType,
|
||||
status,
|
||||
typeName,
|
||||
iconBasePath = this.getBaseUrl(window.location.pathname) + Globals.entityImgPath;
|
||||
if (entityData) {
|
||||
typeName = entityData.typeName;
|
||||
serviceType = entityData && entityData.serviceType;
|
||||
status = entityData && entityData.status;
|
||||
}
|
||||
|
||||
function getImgPath(imageName) {
|
||||
return iconBasePath + (Enums.entityStateReadOnly[status] ? "disabled/" + imageName : imageName);
|
||||
}
|
||||
|
||||
function getDefaultImgPath() {
|
||||
if (entityData.isProcess) {
|
||||
if (Enums.entityStateReadOnly[status]) {
|
||||
return iconBasePath + "disabled/process.png";
|
||||
} else {
|
||||
return iconBasePath + "process.png";
|
||||
}
|
||||
} else {
|
||||
if (Enums.entityStateReadOnly[status]) {
|
||||
return iconBasePath + "disabled/table.png";
|
||||
} else {
|
||||
return iconBasePath + "table.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entityData) {
|
||||
if (errorUrl) {
|
||||
var isErrorInTypeName = errorUrl && errorUrl.match("entity-icon/" + typeName + ".png|disabled/" + typeName + ".png") ? true : false;
|
||||
if (serviceType && isErrorInTypeName) {
|
||||
var imageName = serviceType + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else {
|
||||
return getDefaultImgPath();
|
||||
}
|
||||
} else if (entityData.typeName) {
|
||||
var imageName = entityData.typeName + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else {
|
||||
return getDefaultImgPath();
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* [isProcess description]
|
||||
* @param {[type]} options.typeName [description]
|
||||
* @param {[type]} options.superTypes [description]
|
||||
* @param {[type]} options.entityDef [description]
|
||||
* @return {Boolean} [description]
|
||||
*/
|
||||
isProcess: function({ typeName, superTypes, entityDef }) {
|
||||
if (typeName == "Process") {
|
||||
return true;
|
||||
}
|
||||
return superTypes.indexOf("Process") > -1;
|
||||
},
|
||||
/**
|
||||
* [isDeleted description]
|
||||
* @param {[type]} node [description]
|
||||
* @return {Boolean} [description]
|
||||
*/
|
||||
isDeleted: function(node) {
|
||||
if (node === undefined) {
|
||||
return;
|
||||
}
|
||||
return Enums.entityStateReadOnly[node.status];
|
||||
},
|
||||
isNodeToBeUpdated: function(node, filterObj) {
|
||||
var isProcessHideCheck = filterObj.isProcessHideCheck,
|
||||
isDeletedEntityHideCheck = filterObj.isDeletedEntityHideCheck;
|
||||
var returnObj = {
|
||||
isProcess: isProcessHideCheck && node.isProcess,
|
||||
isDeleted: isDeletedEntityHideCheck && node.isDeleted
|
||||
};
|
||||
returnObj["update"] = returnObj.isProcess || returnObj.isDeleted;
|
||||
return returnObj;
|
||||
},
|
||||
/**
|
||||
* [getServiceType description]
|
||||
* @param {[type]} options.typeName [description]
|
||||
* @param {[type]} options.entityDef [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getServiceType: function({ typeName, entityDef }) {
|
||||
var serviceType = null;
|
||||
if (typeName) {
|
||||
if (entityDef) {
|
||||
serviceType = entityDef.serviceType || null;
|
||||
}
|
||||
}
|
||||
return serviceType;
|
||||
},
|
||||
/**
|
||||
* [getEntityDef description]
|
||||
* @param {[type]} options.typeName [description]
|
||||
* @param {[type]} options.entityDefCollection [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getEntityDef: function({ typeName, entityDefCollection }) {
|
||||
var entityDef = null;
|
||||
if (typeName) {
|
||||
entityDef = entityDefCollection.find(function(obj) {
|
||||
return obj.name == typeName;
|
||||
});
|
||||
}
|
||||
return entityDef;
|
||||
},
|
||||
/**
|
||||
* [getNestedSuperTypes description]
|
||||
* @param {[type]} options.entityDef [description]
|
||||
* @param {[type]} options.entityDefCollection [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getNestedSuperTypes: function({ entityDef, entityDefCollection }) {
|
||||
var data = entityDef,
|
||||
collection = entityDefCollection,
|
||||
superTypes = new Set();
|
||||
|
||||
var getData = function(data, collection) {
|
||||
if (data) {
|
||||
if (data.superTypes && data.superTypes.length) {
|
||||
data.superTypes.forEach(function(superTypeName) {
|
||||
superTypes.add(superTypeName);
|
||||
var collectionData = collection.find(function(obj) {
|
||||
obj.name === superTypeName;
|
||||
});
|
||||
if (collectionData) {
|
||||
getData(collectionData, collection);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
getData(data, collection);
|
||||
return Array.from(superTypes);
|
||||
},
|
||||
generateData: function({ data = {}, filterObj, entityDefCollection, g, guid, setGraphEdge, setGraphNode }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
var relations = data.relations || {},
|
||||
guidEntityMap = data.guidEntityMap || {},
|
||||
isHideFilterOn = filterObj.isProcessHideCheck || filterObj.isDeletedEntityHideCheck,
|
||||
newHashMap = {},
|
||||
styleObj = {
|
||||
fill: "none",
|
||||
stroke: "#ffb203",
|
||||
width: 3
|
||||
},
|
||||
makeNodeData = (relationObj) => {
|
||||
if (relationObj) {
|
||||
if (relationObj.updatedValues) {
|
||||
return relationObj;
|
||||
}
|
||||
var obj = Object.assign(relationObj, {
|
||||
shape: "img",
|
||||
updatedValues: true,
|
||||
label: relationObj.displayText.trunc(18),
|
||||
toolTipLabel: relationObj.displayText,
|
||||
id: relationObj.guid,
|
||||
isLineage: true,
|
||||
isIncomplete: relationObj.isIncomplete,
|
||||
entityDef: this.getEntityDef({ typeName: relationObj.typeName, entityDefCollection })
|
||||
});
|
||||
obj["serviceType"] = this.getServiceType(obj);
|
||||
obj["superTypes"] = this.getNestedSuperTypes({
|
||||
...obj,
|
||||
entityDefCollection: entityDefCollection
|
||||
});
|
||||
obj["isProcess"] = this.isProcess(obj);
|
||||
obj["isDeleted"] = this.isDeleted(obj);
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
crateLineageRelationshipHashMap = function({ relations } = {}) {
|
||||
var newHashMap = {};
|
||||
relations.forEach(function(obj) {
|
||||
if (newHashMap[obj.fromEntityId]) {
|
||||
newHashMap[obj.fromEntityId].push(obj.toEntityId);
|
||||
} else {
|
||||
newHashMap[obj.fromEntityId] = [obj.toEntityId];
|
||||
}
|
||||
});
|
||||
return newHashMap;
|
||||
},
|
||||
getStyleObjStr = function(styleObj) {
|
||||
return "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width;
|
||||
},
|
||||
getNewToNodeRelationship = (toNodeGuid, filterObj) => {
|
||||
if (toNodeGuid && relationshipMap[toNodeGuid]) {
|
||||
var newRelationship = [];
|
||||
relationshipMap[toNodeGuid].forEach((guid) => {
|
||||
var nodeToBeUpdated = this.isNodeToBeUpdated(makeNodeData(guidEntityMap[guid]), filterObj);
|
||||
if (nodeToBeUpdated.update) {
|
||||
var newRelation = getNewToNodeRelationship(guid, filterObj);
|
||||
if (newRelation) {
|
||||
newRelationship = newRelationship.concat(newRelation);
|
||||
}
|
||||
} else {
|
||||
newRelationship.push(guid);
|
||||
}
|
||||
});
|
||||
return newRelationship;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
getToNodeRelation = (toNodes, fromNodeToBeUpdated, filterObj) => {
|
||||
var toNodeRelationship = [];
|
||||
toNodes.forEach((toNodeGuid) => {
|
||||
var toNodeToBeUpdated = this.isNodeToBeUpdated(makeNodeData(guidEntityMap[toNodeGuid]), filterObj);
|
||||
if (toNodeToBeUpdated.update) {
|
||||
// To node need to updated
|
||||
if (pendingFromRelationship[toNodeGuid]) {
|
||||
toNodeRelationship = toNodeRelationship.concat(pendingFromRelationship[toNodeGuid]);
|
||||
} else {
|
||||
var newToNodeRelationship = getNewToNodeRelationship(toNodeGuid, filterObj);
|
||||
if (newToNodeRelationship) {
|
||||
toNodeRelationship = toNodeRelationship.concat(newToNodeRelationship);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//when bothe node not to be updated.
|
||||
toNodeRelationship.push(toNodeGuid);
|
||||
}
|
||||
});
|
||||
return toNodeRelationship;
|
||||
},
|
||||
setNode = (guid) => {
|
||||
if (!g._nodes[guid]) {
|
||||
var nodeData = makeNodeData(guidEntityMap[guid]);
|
||||
setGraphNode(guid, nodeData);
|
||||
return nodeData;
|
||||
} else {
|
||||
return g._nodes[guid];
|
||||
}
|
||||
},
|
||||
setEdge = function(fromNodeGuid, toNodeGuid, opt = {}) {
|
||||
setGraphEdge(fromNodeGuid, toNodeGuid, {
|
||||
arrowhead: "arrowPoint",
|
||||
curve: curveBasis,
|
||||
style: getStyleObjStr(styleObj),
|
||||
styleObj: styleObj,
|
||||
...opt
|
||||
});
|
||||
},
|
||||
setGraphData = function(fromEntityId, toEntityId) {
|
||||
setNode(fromEntityId);
|
||||
setNode(toEntityId);
|
||||
setEdge(fromEntityId, toEntityId);
|
||||
},
|
||||
pendingFromRelationship = {};
|
||||
if (isHideFilterOn) {
|
||||
var relationshipMap = crateLineageRelationshipHashMap(data);
|
||||
Object.keys(relationshipMap).forEach((fromNodeGuid) => {
|
||||
var toNodes = relationshipMap[fromNodeGuid],
|
||||
fromNodeToBeUpdated = this.isNodeToBeUpdated(makeNodeData(guidEntityMap[fromNodeGuid]), filterObj),
|
||||
toNodeList = getToNodeRelation(toNodes, fromNodeToBeUpdated, filterObj);
|
||||
if (fromNodeToBeUpdated.update) {
|
||||
if (pendingFromRelationship[fromNodeGuid]) {
|
||||
pendingFromRelationship[fromNodeGuid] = pendingFromRelationship[fromNodeGuid].concat(toNodeList);
|
||||
} else {
|
||||
pendingFromRelationship[fromNodeGuid] = toNodeList;
|
||||
}
|
||||
} else {
|
||||
toNodeList.forEach(function(toNodeGuid) {
|
||||
setGraphData(fromNodeGuid, toNodeGuid);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
relations.forEach(function(obj) {
|
||||
setGraphData(obj.fromEntityId, obj.toEntityId);
|
||||
});
|
||||
}
|
||||
if (g._nodes[guid]) {
|
||||
if (g._nodes[guid]) {
|
||||
g._nodes[guid]["isLineage"] = false;
|
||||
}
|
||||
this.findImpactNodeAndUpdateData({
|
||||
guid,
|
||||
g,
|
||||
setEdge,
|
||||
getStyleObjStr
|
||||
});
|
||||
}
|
||||
resolve(g);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
},
|
||||
findImpactNodeAndUpdateData: function({ guid, getStyleObjStr, g, setEdge }) {
|
||||
var that = this,
|
||||
traversedMap = {},
|
||||
styleObj = {
|
||||
fill: "none",
|
||||
stroke: "#fb4200",
|
||||
width: 3
|
||||
},
|
||||
traversed = function(toNodeList = {}, fromNodeGuid) {
|
||||
let toNodeKeyList = Object.keys(toNodeList);
|
||||
if (toNodeKeyList.length) {
|
||||
if (!traversedMap[fromNodeGuid]) {
|
||||
traversedMap[fromNodeGuid] = true;
|
||||
toNodeKeyList.forEach(function(toNodeGuid) {
|
||||
if (g._nodes[toNodeGuid]) {
|
||||
g._nodes[toNodeGuid]["isLineage"] = false;
|
||||
}
|
||||
setEdge(fromNodeGuid, toNodeGuid, {
|
||||
style: getStyleObjStr(styleObj),
|
||||
styleObj: styleObj
|
||||
});
|
||||
traversed(g._sucs[toNodeGuid], toNodeGuid);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
traversed(g._sucs[guid], guid);
|
||||
}
|
||||
};
|
||||
export default DataUtils;
|
||||
|
|
@ -0,0 +1,608 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { select, event } from "d3-selection";
|
||||
import { zoom, zoomIdentity } from "d3-zoom";
|
||||
import { drag } from "d3-drag";
|
||||
import { line, curveBasis } from "d3-shape";
|
||||
|
||||
import platform from "platform";
|
||||
|
||||
import Enums from "../Enums";
|
||||
|
||||
const LineageUtils = {
|
||||
/**
|
||||
* [nodeArrowDistance variable use to define the distance between arrow and node]
|
||||
* @type {Number}
|
||||
*/
|
||||
nodeArrowDistance: 24,
|
||||
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);
|
||||
});
|
||||
},
|
||||
refreshGraphForIE: function ({ edgePathEl }) {
|
||||
var 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);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* [dragNode description]
|
||||
* @param {[type]} options.g [description]
|
||||
* @param {[type]} options.svg [description]
|
||||
* @param {[type]} options.guid [description]
|
||||
* @param {[type]} options.edgePathEl [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
dragNode: function ({ g, svg, guid, edgePathEl }) {
|
||||
var dragHelper = {
|
||||
dragmove: function (el, d) {
|
||||
var node = select(el),
|
||||
selectedNode = g.node(d),
|
||||
prevX = selectedNode.x,
|
||||
prevY = selectedNode.y;
|
||||
|
||||
selectedNode.x += event.dx;
|
||||
selectedNode.y += event.dy;
|
||||
node.attr("transform", "translate(" + selectedNode.x + "," + selectedNode.y + ")");
|
||||
|
||||
var dx = selectedNode.x - prevX,
|
||||
dy = selectedNode.y - prevY;
|
||||
|
||||
g.edges().forEach((e) => {
|
||||
if (e.v == d || e.w == d) {
|
||||
var edge = g.edge(e.v, e.w);
|
||||
this.translateEdge(edge, dx, dy);
|
||||
select(edge.elem).select("path").attr("d", this.calcPoints(e));
|
||||
}
|
||||
});
|
||||
//LineageUtils.refreshGraphForIE({ edgePathEl: 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 line()
|
||||
.x(function (d) {
|
||||
return d.x;
|
||||
})
|
||||
.y(function (d) {
|
||||
return d.y;
|
||||
})
|
||||
.curve(curveBasis)(points);
|
||||
},
|
||||
intersectRect: (node, point) => {
|
||||
var x = node.x,
|
||||
y = node.y,
|
||||
dx = point.x - x,
|
||||
dy = point.y - y,
|
||||
nodeDistance = guid ? this.nodeArrowDistance + 3 : this.nodeArrowDistance,
|
||||
w = nodeDistance,
|
||||
h = nodeDistance,
|
||||
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
|
||||
};
|
||||
}
|
||||
};
|
||||
var dragNodeHandler = drag().on("drag", function (d) {
|
||||
dragHelper.dragmove.call(dragHelper, this, d);
|
||||
}),
|
||||
dragEdgePathHandler = drag().on("drag", function (d) {
|
||||
dragHelper.translateEdge(g.edge(d.v, d.w), event.dx, event.dy);
|
||||
var edgeObj = g.edge(d.v, d.w);
|
||||
select(edgeObj.elem).select("path").attr("d", dragHelper.calcPoints(d));
|
||||
});
|
||||
|
||||
dragNodeHandler(svg.selectAll("g.node"));
|
||||
dragEdgePathHandler(svg.selectAll("g.edgePath"));
|
||||
},
|
||||
zoomIn: function ({ svg, scaleFactor = 1.3 }) {
|
||||
this.d3Zoom.scaleBy(svg.transition().duration(750), scaleFactor);
|
||||
},
|
||||
zoomOut: function ({ svg, scaleFactor = 0.8 }) {
|
||||
this.d3Zoom.scaleBy(svg.transition().duration(750), scaleFactor);
|
||||
},
|
||||
zoom: function ({ svg, xa, ya, scale }) {
|
||||
svg.transition().duration(750).call(this.d3Zoom.transform, zoomIdentity.translate(xa, ya).scale(scale));
|
||||
},
|
||||
fitToScreen: function ({ svg }) {
|
||||
var node = svg.node();
|
||||
var bounds = node.getBBox();
|
||||
|
||||
var parent = node.parentElement,
|
||||
fullWidth = parent.clientWidth,
|
||||
fullHeight = parent.clientHeight;
|
||||
|
||||
var width = bounds.width,
|
||||
height = bounds.height;
|
||||
var midX = bounds.x + width / 2,
|
||||
midY = bounds.y + height / 2;
|
||||
|
||||
var scale = (scale || 0.95) / Math.max(width / fullWidth, height / fullHeight),
|
||||
xa = fullWidth / 2 - scale * midX,
|
||||
ya = fullHeight / 2 - scale * midY;
|
||||
this.zoom({ svg, xa, ya, scale });
|
||||
},
|
||||
/**
|
||||
* [centerNode description]
|
||||
* @param {[type]} options.guid [description]
|
||||
* @param {[type]} options.g [description]
|
||||
* @param {[type]} options.svg [description]
|
||||
* @param {[type]} options.svgGroupEl [description]
|
||||
* @param {[type]} options.edgePathEl [description]
|
||||
* @param {[type]} options.width [description]
|
||||
* @param {[type]} options.height [description]
|
||||
* @param {[type]} options.onCenterZoomed [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
centerNode: function ({ guid, g, svg, svgGroupEl, edgePathEl, width, height, fitToScreen, onCenterZoomed }) {
|
||||
this.d3Zoom = zoom();
|
||||
svg.call(this.d3Zoom).on("dblclick.zoom", null);
|
||||
|
||||
// restrict events
|
||||
|
||||
let selectedNodeEl = svg.selectAll("g.nodes>g[id='" + guid + "']"),
|
||||
zoomListener = this.d3Zoom.scaleExtent([0.01, 50]).on("zoom", function () {
|
||||
svgGroupEl.attr("transform", event.transform);
|
||||
}),
|
||||
x = null,
|
||||
y = null,
|
||||
scale = 1.2;
|
||||
if (selectedNodeEl.empty()) {
|
||||
if (fitToScreen) {
|
||||
this.fitToScreen({ svg });
|
||||
return;
|
||||
} else {
|
||||
x = g.graph().width / 2;
|
||||
y = g.graph().height / 2;
|
||||
}
|
||||
} else {
|
||||
var matrix = selectedNodeEl
|
||||
.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(" ");
|
||||
// }
|
||||
x = matrix[0];
|
||||
y = matrix[1];
|
||||
}
|
||||
|
||||
var xa = -(x * scale - width / 2),
|
||||
ya = -(y * scale - height / 2);
|
||||
this.zoom({ svg, xa, ya, scale });
|
||||
svg.transition().duration(750).call(this.d3Zoom.transform, zoomIdentity.translate(xa, ya).scale(scale));
|
||||
|
||||
if (onCenterZoomed) {
|
||||
onCenterZoomed({ newScale: scale, newTranslate: [xa, ya], d3Zoom: this.d3Zoom, selectedNodeEl });
|
||||
}
|
||||
// if (platform.name === "IE") {
|
||||
// LineageUtils.refreshGraphForIE({ edgePathEl: edgePathEl });
|
||||
// }
|
||||
},
|
||||
/**
|
||||
* [getToolTipDirection description]
|
||||
* @param {[type]} options.el [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getToolTipDirection: function ({ el }) {
|
||||
var width = select("body").node().getBoundingClientRect().width,
|
||||
currentELWidth = select(el).node().getBoundingClientRect(),
|
||||
direction = "e";
|
||||
if (width - currentELWidth.left < 330) {
|
||||
direction = width - currentELWidth.left < 330 && currentELWidth.top < 400 ? "sw" : "w";
|
||||
if (width - currentELWidth.left < 330 && currentELWidth.top > 600) {
|
||||
direction = "nw";
|
||||
}
|
||||
} else if (currentELWidth.top > 600) {
|
||||
direction = width - currentELWidth.left < 330 && currentELWidth.top > 600 ? "nw" : "n";
|
||||
if (currentELWidth.left < 50) {
|
||||
direction = "ne";
|
||||
}
|
||||
} else if (currentELWidth.top < 400) {
|
||||
direction = currentELWidth.left < 50 ? "se" : "s";
|
||||
}
|
||||
return direction;
|
||||
},
|
||||
/**
|
||||
* [onHoverFade description]
|
||||
* @param {[type]} options.svg [description]
|
||||
* @param {[type]} options.g [description]
|
||||
* @param {[type]} options.mouseenter [description]
|
||||
* @param {[type]} options.opacity [description]
|
||||
* @param {[type]} options.nodesToHighlight [description]
|
||||
* @param {[type]} options.hoveredNode [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
onHoverFade: function ({ svg, g, mouseenter, nodesToHighlight, hoveredNode }) {
|
||||
var node = svg.selectAll(".node"),
|
||||
path = svg.selectAll(".edgePath"),
|
||||
isConnected = function (a, b, o) {
|
||||
if (a === o || (b && b.length && b.indexOf(o) != -1)) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if (mouseenter) {
|
||||
svg.classed("hover", true);
|
||||
var nextNode = g.successors(hoveredNode),
|
||||
previousNode = g.predecessors(hoveredNode),
|
||||
nodesToHighlight = nextNode.concat(previousNode);
|
||||
node.classed("hover-active-node", function (currentNode, i, nodes) {
|
||||
if (isConnected(hoveredNode, nodesToHighlight, currentNode)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
path.classed("hover-active-path", function (c) {
|
||||
var _thisOpacity = c.v === hoveredNode || c.w === hoveredNode ? 1 : 0;
|
||||
if (_thisOpacity) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
svg.classed("hover", false);
|
||||
node.classed("hover-active-node", false);
|
||||
path.classed("hover-active-path", false);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* [getBaseUrl description]
|
||||
* @param {[type]} path [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getBaseUrl: function (url = window.location.pathname) {
|
||||
return url.replace(/\/[\w-]+.(jsp|html)|\/+$/gi, "");
|
||||
},
|
||||
getEntityIconPath: function ({ entityData, errorUrl, imgBasePath }) {
|
||||
var iconBasePath = this.getBaseUrl() + (imgBasePath || "/img/entity-icon/");
|
||||
if (entityData) {
|
||||
let { typeName, serviceType, status, isProcess } = entityData;
|
||||
|
||||
function getImgPath(imageName) {
|
||||
return iconBasePath + (Enums.entityStateReadOnly[status] ? "disabled/" + imageName : imageName);
|
||||
}
|
||||
|
||||
function getDefaultImgPath() {
|
||||
if (isProcess) {
|
||||
if (Enums.entityStateReadOnly[status]) {
|
||||
return iconBasePath + "disabled/process.png";
|
||||
} else {
|
||||
return iconBasePath + "process.png";
|
||||
}
|
||||
} else {
|
||||
if (Enums.entityStateReadOnly[status]) {
|
||||
return iconBasePath + "disabled/table.png";
|
||||
} else {
|
||||
return iconBasePath + "table.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errorUrl) {
|
||||
// Check if the default img path has error, if yes then stop recursion.
|
||||
if (errorUrl.indexOf("table.png") > -1 || errorUrl.indexOf("process.png") > -1) {
|
||||
return null;
|
||||
}
|
||||
var isErrorInTypeName = errorUrl && errorUrl.match("entity-icon/" + typeName + ".png|disabled/" + typeName + ".png") ? true : false;
|
||||
if (serviceType && isErrorInTypeName) {
|
||||
var imageName = serviceType + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else {
|
||||
return getDefaultImgPath();
|
||||
}
|
||||
} else if (typeName) {
|
||||
var imageName = typeName + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else if (serviceType) {
|
||||
var imageName = serviceType + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else {
|
||||
return getDefaultImgPath();
|
||||
}
|
||||
}
|
||||
},
|
||||
base64Encode: function (file, callback) {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", () => callback(reader.result));
|
||||
reader.readAsDataURL(file);
|
||||
},
|
||||
imgShapeRender: function (parent, bbox, node, { dagreD3, defsEl, imgBasePath, guid }) {
|
||||
var that = this,
|
||||
viewGuid = guid,
|
||||
imageIconPath = this.getEntityIconPath({ entityData: node, imgBasePath }),
|
||||
imgName = imageIconPath.split("/").pop();
|
||||
if (this.imageObject === undefined) {
|
||||
this.imageObject = {};
|
||||
}
|
||||
if (node.isDeleted) {
|
||||
imgName = "deleted_" + imgName;
|
||||
}
|
||||
if (node.id == viewGuid) {
|
||||
var currentNode = true;
|
||||
}
|
||||
var shapeSvg = parent
|
||||
.append("circle")
|
||||
.attr("fill", "url(#img_" + imgName + ")")
|
||||
.attr("r", "24px")
|
||||
.attr("data-stroke", node.id)
|
||||
.attr("stroke-width", "2px")
|
||||
.attr("class", "nodeImage " + (currentNode ? "currentNode" : node.isProcess ? "process" : "node"));
|
||||
if (currentNode) {
|
||||
shapeSvg.attr("stroke", "#fb4200");
|
||||
}
|
||||
if (node.isIncomplete === true) {
|
||||
parent.attr("class", "node isIncomplete show");
|
||||
parent
|
||||
.insert("foreignObject")
|
||||
.attr("x", "-25")
|
||||
.attr("y", "-25")
|
||||
.attr("width", "50")
|
||||
.attr("height", "50")
|
||||
.append("xhtml:div")
|
||||
.insert("i")
|
||||
.attr("class", "fa fa-hourglass-half");
|
||||
}
|
||||
|
||||
if (defsEl.select('pattern[id="img_' + imgName + '"]').empty()) {
|
||||
defsEl
|
||||
.append("pattern")
|
||||
.attr("x", "0%")
|
||||
.attr("y", "0%")
|
||||
.attr("patternUnits", "objectBoundingBox")
|
||||
.attr("id", "img_" + imgName)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.append("image")
|
||||
.attr("href", function (d) {
|
||||
var imgEl = this;
|
||||
if (node) {
|
||||
var getImageData = function (options) {
|
||||
var imagePath = options.imagePath,
|
||||
ajaxOptions = {
|
||||
url: imagePath,
|
||||
method: "GET",
|
||||
cache: true
|
||||
};
|
||||
|
||||
// if (platform.name !== "IE") {
|
||||
// ajaxOptions["mimeType"] = "text/plain; charset=x-user-defined";
|
||||
// }
|
||||
shapeSvg.attr("data-iconpath", imagePath);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
if (platform.name !== "IE") {
|
||||
that.base64Encode(this.response, (url) => {
|
||||
that.imageObject[imageIconPath] = url;
|
||||
select(imgEl).attr("xlink:href", url);
|
||||
});
|
||||
} else {
|
||||
that.imageObject[imageIconPath] = imagePath;
|
||||
}
|
||||
if (imageIconPath !== shapeSvg.attr("data-iconpath")) {
|
||||
shapeSvg.attr("data-iconpathorigin", imageIconPath);
|
||||
}
|
||||
} else if (xhr.status === 404) {
|
||||
const imgPath = that.getEntityIconPath({ entityData: node, errorUrl: imagePath });
|
||||
if (imgPath === null) {
|
||||
const patternEL = select(imgEl.parentElement);
|
||||
patternEL.select("image").remove();
|
||||
patternEL
|
||||
.attr("patternContentUnits", "objectBoundingBox")
|
||||
.append("circle")
|
||||
.attr("r", "24px")
|
||||
.attr("fill", "#e8e8e8");
|
||||
} else {
|
||||
getImageData({
|
||||
imagePath: imgPath
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.responseType = "blob";
|
||||
xhr.open(ajaxOptions.method, ajaxOptions.url, true);
|
||||
xhr.send(null);
|
||||
};
|
||||
getImageData({
|
||||
imagePath: imageIconPath
|
||||
});
|
||||
}
|
||||
})
|
||||
.attr("x", "4")
|
||||
.attr("y", currentNode ? "3" : "4")
|
||||
.attr("width", "40")
|
||||
.attr("height", "40");
|
||||
}
|
||||
|
||||
node.intersect = function (point) {
|
||||
return dagreD3.intersect.circle(node, currentNode ? that.nodeArrowDistance + 3 : that.nodeArrowDistance, point);
|
||||
};
|
||||
return shapeSvg;
|
||||
},
|
||||
/**
|
||||
* [arrowPointRender description]
|
||||
* @param {[type]} {parent, id, edge, type, viewOptions [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
arrowPointRender: function (parent, id, edge, type, { dagreD3 }) {
|
||||
var node = parent.node(),
|
||||
parentNode = node ? node.parentNode : parent;
|
||||
select(parentNode)
|
||||
.select("path.path")
|
||||
.attr("marker-end", "url(#" + id + ")");
|
||||
var marker = parent
|
||||
.append("marker")
|
||||
.attr("id", id)
|
||||
.attr("viewBox", "0 0 10 10")
|
||||
.attr("refX", 8)
|
||||
.attr("refY", 5)
|
||||
.attr("markerUnits", "strokeWidth")
|
||||
.attr("markerWidth", 4)
|
||||
.attr("markerHeight", 4)
|
||||
.attr("orient", "auto");
|
||||
|
||||
var path = marker.append("path").attr("d", "M 0 0 L 10 5 L 0 10 z").style("fill", edge.styleObj.stroke);
|
||||
dagreD3.util.applyStyle(path, edge[type + "Style"]);
|
||||
},
|
||||
/**
|
||||
* [saveSvg description]
|
||||
* @param {[type]} options.svg [description]
|
||||
* @param {[type]} options.width [description]
|
||||
* @param {[type]} options.height [description]
|
||||
* @param {[type]} options.downloadFileName [description]
|
||||
* @param {[type]} options.onExportLineage [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
saveSvg: function ({ svg, width, height, downloadFileName, onExportLineage }) {
|
||||
var that = this,
|
||||
svgClone = svg.clone(true).node(),
|
||||
scaleFactor = 1;
|
||||
setTimeout(function () {
|
||||
if (platform.name === "Firefox") {
|
||||
svgClone.setAttribute("width", width);
|
||||
svgClone.setAttribute("height", height);
|
||||
}
|
||||
const hiddenSvgEl = select("body").append("div");
|
||||
hiddenSvgEl.classed("hidden-svg", true);
|
||||
hiddenSvgEl.node().appendChild(svgClone);
|
||||
|
||||
const svgCloneEl = select(".hidden-svg svg");
|
||||
svgCloneEl.select("g").attr("transform", "scale(" + scaleFactor + ")");
|
||||
svgCloneEl.select("foreignObject").remove();
|
||||
|
||||
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 canvas = document.createElement("canvas");
|
||||
canvas.id = "canvas";
|
||||
canvas.style.display = "none";
|
||||
canvas.width = svgClone.getBBox().width * scaleFactor + canvasOffset.x;
|
||||
canvas.height = svgClone.getBBox().height * scaleFactor + canvasOffset.y;
|
||||
|
||||
// Append Canvas in DOM
|
||||
select("body").node().appendChild(canvas);
|
||||
|
||||
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");
|
||||
a.download = downloadFileName;
|
||||
document.body.appendChild(a);
|
||||
ctx.drawImage(img, 50, 50, canvas.width, canvas.height);
|
||||
canvas.toBlob(function (blob) {
|
||||
if (!blob) {
|
||||
onExportLineage({ status: "failed", message: "There was an error in downloading Lineage!" });
|
||||
return;
|
||||
}
|
||||
a.href = DOMURL.createObjectURL(blob);
|
||||
if (blob.size > 10000000) {
|
||||
onExportLineage({ status: "failed", message: "The Image size is huge, please open the image in a browser!" });
|
||||
}
|
||||
a.click();
|
||||
onExportLineage({ status: "Success", message: "Successful" });
|
||||
if (platform.name === "Safari") {
|
||||
that.refreshGraphForSafari({
|
||||
edgeEl: that.$("svg g.node")
|
||||
});
|
||||
}
|
||||
}, "image/png");
|
||||
hiddenSvgEl.remove();
|
||||
canvas.remove();
|
||||
} catch (err) {
|
||||
onExportLineage({ status: "failed", message: "There was an error in downloading Lineage!" });
|
||||
}
|
||||
};
|
||||
img.src = url;
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
export default LineageUtils;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import LineageUtils from "./LineageUtils";
|
||||
import DataUtils from "./DataUtils";
|
||||
|
||||
String.prototype.trunc =
|
||||
String.prototype.trunc ||
|
||||
function(n) {
|
||||
return this.length > n ? this.substr(0, n - 1) + "..." : this;
|
||||
};
|
||||
|
||||
export { LineageUtils, DataUtils };
|
||||
|
|
@ -0,0 +1,611 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import dagreD3 from "dagre-d3";
|
||||
import { select, selection, event } from "d3-selection";
|
||||
import { curveBasis } from "d3-shape";
|
||||
import { LineageUtils, DataUtils } from "./Utils";
|
||||
import d3Tip from "d3-tip";
|
||||
|
||||
import "./styles/style.scss";
|
||||
|
||||
export default class LineageHelper {
|
||||
constructor(options) {
|
||||
this._updateOptions(options);
|
||||
const { el, manualTrigger = false } = this.options;
|
||||
if (el === undefined) {
|
||||
throw new Error("LineageHelper requires el propety to render the graph");
|
||||
}
|
||||
this.initReturnObj = {
|
||||
init: (arg) => this.init(arg),
|
||||
createGraph: (opt = {}) => this._createGraph(this.options, this.graphOptions, opt),
|
||||
clear: (arg) => this.clear(arg),
|
||||
refresh: (arg) => this.refresh(arg),
|
||||
centerAlign: (arg) => this.centerAlign(arg),
|
||||
exportLineage: (arg) => this.exportLineage(arg),
|
||||
zoomIn: (arg) => this.zoomIn(arg),
|
||||
zoomOut: (arg) => this.zoomOut(arg),
|
||||
zoom: (arg) => this.zoom(arg),
|
||||
fullScreen: (arg) => this.fullScreen(arg),
|
||||
searchNode: (arg) => this.searchNode(arg),
|
||||
removeNodeSelection: (arg) => this.removeNodeSelection(arg),
|
||||
getGraphOptions: () => this.graphOptions,
|
||||
getNode: (guid, actual) => {
|
||||
let rObj = null;
|
||||
if (actual) {
|
||||
rObj = this.actualData[guid];
|
||||
} else {
|
||||
rObj = this.g._nodes[guid];
|
||||
}
|
||||
if (rObj) {
|
||||
rObj = Object.assign({}, rObj);
|
||||
}
|
||||
return rObj;
|
||||
},
|
||||
getNodes: (guid, actual) => {
|
||||
let rObj = null;
|
||||
if (actual) {
|
||||
rObj = this.actualData;
|
||||
} else {
|
||||
rObj = this.g._nodes;
|
||||
}
|
||||
if (rObj) {
|
||||
rObj = Object.assign({}, rObj);
|
||||
}
|
||||
return rObj;
|
||||
},
|
||||
setNode: this._setGraphNode,
|
||||
setEdge: this._setGraphEdge
|
||||
};
|
||||
if (manualTrigger === false) {
|
||||
this.init();
|
||||
}
|
||||
return this.initReturnObj;
|
||||
}
|
||||
/**
|
||||
* [updateOptions get the options from user and appedn add it in this,option context]
|
||||
* @param {[Object]} options [lib options from user]
|
||||
* @return {[null]} [null]
|
||||
*/
|
||||
_updateOptions(options) {
|
||||
this.options = {};
|
||||
Object.assign(this.options, { filterObj: { isProcessHideCheck: false, isDeletedEntityHideCheck: false } }, options);
|
||||
}
|
||||
/**
|
||||
* [init Start the graph build process]
|
||||
* @return {[null]} [null]
|
||||
*/
|
||||
init() {
|
||||
const { data = {} } = this.options;
|
||||
if (data.baseEntityGuid) {
|
||||
this.guid = data.baseEntityGuid;
|
||||
}
|
||||
// Call the initializeGraph method to initlize dagreD3 graphlib
|
||||
this._initializeGraph();
|
||||
this._initGraph();
|
||||
}
|
||||
/**
|
||||
* [clear Allows user to clear the graph refrence and dom]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
clear() {
|
||||
if (!this.options.el) {
|
||||
this.svg.remove();
|
||||
this.svg = null;
|
||||
}
|
||||
this.g = null;
|
||||
this.graphOptions = {};
|
||||
}
|
||||
/**
|
||||
* [centerAlign Allows user to center the lineage position, without rerender]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
centerAlign(opt = {}) {
|
||||
var svgGroupEl = this.svg.select("g"),
|
||||
edgePathEl = svgGroupEl.selectAll("g.edgePath");
|
||||
LineageUtils.centerNode({
|
||||
...this.graphOptions,
|
||||
svgGroupEl,
|
||||
edgePathEl,
|
||||
...opt
|
||||
});
|
||||
}
|
||||
/**
|
||||
* [zoomIn description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
zoomIn(opt = {}) {
|
||||
LineageUtils.zoomIn({ ...this.graphOptions, ...opt });
|
||||
}
|
||||
/**
|
||||
* [zoomOut description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
zoomOut(opt = {}) {
|
||||
LineageUtils.zoomOut({ ...this.graphOptions, ...opt });
|
||||
}
|
||||
/**
|
||||
* [zoom description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
zoom(opt = {}) {
|
||||
LineageUtils.zoom({ ...this.graphOptions, ...opt });
|
||||
}
|
||||
/**
|
||||
* [refresh Allows user to rerender the lineage]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
refresh() {
|
||||
this.clear();
|
||||
this._initializeGraph();
|
||||
this._initGraph({ refresh: true });
|
||||
}
|
||||
/**
|
||||
* [removeNodeSelection description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
removeNodeSelection() {
|
||||
this.svg.selectAll("g.node>circle").classed("node-detail-highlight", false);
|
||||
}
|
||||
/**
|
||||
* [searchNode description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
searchNode({ guid, onSearchNode }) {
|
||||
this.svg.selectAll(".serach-rect").remove();
|
||||
this.centerAlign({
|
||||
guid: guid,
|
||||
onCenterZoomed: function (opts) {
|
||||
const { selectedNodeEl } = opts;
|
||||
selectedNodeEl.select(".label").attr("stroke", "#316132");
|
||||
selectedNodeEl.select("circle").classed("wobble", true);
|
||||
selectedNodeEl
|
||||
.insert("rect", "circle")
|
||||
.attr("class", "serach-rect")
|
||||
.attr("x", -50)
|
||||
.attr("y", -27.5)
|
||||
.attr("width", 100)
|
||||
.attr("height", 55);
|
||||
if (onSearchNode && typeof onSearchNode === "function") {
|
||||
onSearchNode(opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [exportLineage description]
|
||||
* @param {Object} options [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
exportLineage(options = {}) {
|
||||
let downloadFileName = options.downloadFileName;
|
||||
if (downloadFileName === undefined) {
|
||||
let node = this.g._nodes[this.guid];
|
||||
if (node && node.attributes) {
|
||||
downloadFileName = `${node.attributes.qualifiedName || node.attributes.name || "lineage_export"}.png`;
|
||||
} else {
|
||||
downloadFileName = "lineage_export.png";
|
||||
}
|
||||
}
|
||||
|
||||
LineageUtils.saveSvg({
|
||||
...this.graphOptions,
|
||||
downloadFileName: downloadFileName,
|
||||
onExportLineage: (opt) => {
|
||||
if (options.onExportLineage) {
|
||||
onExportLineage(opt);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* [fullScreen description]
|
||||
* @param {Object} options.el } [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
fullScreen({ el } = {}) {
|
||||
if (el === undefined) {
|
||||
throw new Error("LineageHelper requires el propety to apply fullScreen class");
|
||||
}
|
||||
const fullScreenEl = select(el);
|
||||
if (fullScreenEl.classed("fullscreen-mode")) {
|
||||
fullScreenEl.classed("fullscreen-mode", false);
|
||||
return false;
|
||||
} else {
|
||||
fullScreenEl.classed("fullscreen-mode", true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* [_getValueFromUser description]
|
||||
* @param {[type]} ref [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_getValueFromUser(ref) {
|
||||
if (ref !== undefined) {
|
||||
if (typeof ref === "function") {
|
||||
return ref();
|
||||
} else {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* [initializeGraph initlize the dagreD3 graphlib]
|
||||
* @return {[null]} [null]
|
||||
*/
|
||||
_initializeGraph() {
|
||||
const { width = "100%", height = "100%", el } = this.options;
|
||||
|
||||
// Append the svg using d3.
|
||||
this.svg = select(el);
|
||||
|
||||
if (!(el instanceof SVGElement)) {
|
||||
this.svg = this.svg
|
||||
.append("svg")
|
||||
.attr("xmlns", "http://www.w3.org/2000/svg")
|
||||
.attr(" xmlns:xlink", "http://www.w3.org/1999/xlink")
|
||||
.attr("version", "1.1")
|
||||
.attr("width", width)
|
||||
.attr("height", height);
|
||||
}
|
||||
// initlize the dagreD3 graphlib
|
||||
this.g = new dagreD3.graphlib.Graph()
|
||||
.setGraph(
|
||||
Object.assign(
|
||||
{
|
||||
nodesep: 50,
|
||||
ranksep: 90,
|
||||
rankdir: "LR",
|
||||
marginx: 20,
|
||||
marginy: 20,
|
||||
transition: function transition(selection) {
|
||||
return selection.transition().duration(500);
|
||||
}
|
||||
},
|
||||
this.options.dagreOptions
|
||||
)
|
||||
)
|
||||
.setDefaultEdgeLabel(function () {
|
||||
return {};
|
||||
});
|
||||
|
||||
// Create graphOptions for common use
|
||||
var svgRect = this.svg.node().getBoundingClientRect();
|
||||
this.actualData = {};
|
||||
this.graphOptions = {
|
||||
svg: this.svg,
|
||||
g: this.g,
|
||||
dagreD3: dagreD3,
|
||||
guid: this.guid,
|
||||
width: this.options.width || svgRect.width,
|
||||
height: this.options.height || svgRect.height
|
||||
};
|
||||
}
|
||||
/**
|
||||
* [_initGraph description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_initGraph({ refresh } = {}) {
|
||||
if (this.svg) {
|
||||
this.svg.select("g").remove();
|
||||
}
|
||||
let filterObj = this.options.filterObj;
|
||||
if (this.options.getFilterObj) {
|
||||
let filterObjVal = this.options.getFilterObj();
|
||||
if (filterObjVal !== undefined || filterObjVal !== null) {
|
||||
if (typeof filterObjVal === "object") {
|
||||
filterObj = filterObjVal;
|
||||
} else {
|
||||
throw new Error("getFilterObj expect return type `object`,`null` or `Undefined`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.setDataManually === true) {
|
||||
return;
|
||||
} else if (this.options.data === undefined || (this.options.data && this.options.data.relations.length === 0)) {
|
||||
if (this.options.beforeRender) {
|
||||
this.options.beforeRender();
|
||||
}
|
||||
this.svg
|
||||
.append("text")
|
||||
.attr("x", "50%")
|
||||
.attr("y", "50%")
|
||||
.attr("alignment-baseline", "middle")
|
||||
.attr("text-anchor", "middle")
|
||||
.text("No lineage data found");
|
||||
if (this.options.afterRender) {
|
||||
this.options.afterRender();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return DataUtils.generateData({
|
||||
...this.options,
|
||||
filterObj: filterObj,
|
||||
...this.graphOptions,
|
||||
setGraphNode: this._setGraphNode,
|
||||
setGraphEdge: this._setGraphEdge
|
||||
}).then((graphObj) => {
|
||||
this._createGraph(this.options, this.graphOptions, { refresh });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [description]
|
||||
* @param {[type]} guid [description]
|
||||
* @param {[type]} nodeData [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_setGraphNode = (guid, nodeData) => {
|
||||
this.actualData[guid] = Object.assign({}, nodeData);
|
||||
this.g.setNode(guid, nodeData);
|
||||
};
|
||||
|
||||
/**
|
||||
* [description]
|
||||
* @param {[type]} fromGuid [description]
|
||||
* @param {[type]} toGuid [description]
|
||||
* @param {[type]} opts [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_setGraphEdge = (fromGuid, toGuid, opts) => {
|
||||
this.g.setEdge(fromGuid, toGuid, {
|
||||
curve: curveBasis,
|
||||
...opts
|
||||
});
|
||||
};
|
||||
/**
|
||||
* [_createGraph description]
|
||||
* @param {Object} options.data [description]
|
||||
* @param {Boolean} isShowTooltip [description]
|
||||
* @param {Boolean} isShowHoverPath [description]
|
||||
* @param {[type]} onLabelClick [description]
|
||||
* @param {[type]} onPathClick [description]
|
||||
* @param {[type]} onNodeClick } [description]
|
||||
* @param {[type]} graphOptions [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_createGraph(
|
||||
{ data = {}, imgBasePath, isShowTooltip, isShowHoverPath, onLabelClick, onPathClick, onNodeClick, zoom, fitToScreen },
|
||||
graphOptions,
|
||||
{ refresh }
|
||||
) {
|
||||
if (this.options.beforeRender) {
|
||||
this.options.beforeRender();
|
||||
}
|
||||
const that = this,
|
||||
{ svg, g, width, height } = graphOptions;
|
||||
|
||||
if (svg instanceof selection === false) {
|
||||
throw new Error("svg is not initialized or something went wrong while creatig graph instance");
|
||||
return;
|
||||
}
|
||||
if (g._nodes === undefined || g._nodes.length === 0) {
|
||||
svg.html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>');
|
||||
return;
|
||||
}
|
||||
|
||||
g.nodes().forEach(function (v) {
|
||||
var node = g.node(v);
|
||||
// Round the corners of the nodes
|
||||
if (node) {
|
||||
node.rx = node.ry = 5;
|
||||
}
|
||||
});
|
||||
|
||||
svg.attr("viewBox", "0 0 " + width + " " + height).attr("enable-background", "new 0 0 " + width + " " + height);
|
||||
var svgGroupEl = svg.append("g");
|
||||
|
||||
// Append defs
|
||||
var defsEl = svg.append("defs");
|
||||
|
||||
// Create the renderer
|
||||
var render = new dagreD3.render();
|
||||
// Add our custom arrow (a hollow-point)
|
||||
render.arrows().arrowPoint = function () {
|
||||
return LineageUtils.arrowPointRender(...arguments, { ...graphOptions });
|
||||
};
|
||||
// Render custom img inside shape
|
||||
render.shapes().img = function () {
|
||||
return LineageUtils.imgShapeRender(...arguments, {
|
||||
...graphOptions,
|
||||
imgBasePath: that._getValueFromUser(imgBasePath),
|
||||
defsEl
|
||||
});
|
||||
};
|
||||
|
||||
var tooltip = d3Tip()
|
||||
.attr("class", "d3-tip")
|
||||
.offset([10, 0])
|
||||
.html((d) => {
|
||||
var value = g.node(d);
|
||||
var htmlStr = "";
|
||||
if (value.id !== this.guid) {
|
||||
htmlStr = "<h5 style='text-align: center;'>" + (value.isLineage ? "Lineage" : "Impact") + "</h5>";
|
||||
}
|
||||
htmlStr += "<h5 class='text-center'><span style='color:#359f89'>" + value.toolTipLabel + "</span></h5> ";
|
||||
if (value.typeName) {
|
||||
htmlStr += "<h5 class='text-center'><span>(" + value.typeName + ")</span></h5> ";
|
||||
}
|
||||
if (value.queryText) {
|
||||
htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> ";
|
||||
}
|
||||
return "<div class='tip-inner-scroll'>" + htmlStr + "</div>";
|
||||
});
|
||||
|
||||
svg.call(tooltip);
|
||||
|
||||
// if (platform.name !== "IE") {
|
||||
// this.$(".fontLoader").hide();
|
||||
// }
|
||||
|
||||
render(svgGroupEl, g);
|
||||
|
||||
//change text postion
|
||||
svgGroupEl
|
||||
.selectAll("g.nodes g.label")
|
||||
.attr("transform", "translate(2,-35)")
|
||||
.on("mouseenter", function (d) {
|
||||
event.preventDefault();
|
||||
select(this).classed("highlight", true);
|
||||
})
|
||||
.on("mouseleave", function (d) {
|
||||
event.preventDefault();
|
||||
select(this).classed("highlight", false);
|
||||
})
|
||||
.on("click", function (d) {
|
||||
event.preventDefault();
|
||||
if (onLabelClick && typeof onLabelClick === "function") {
|
||||
onLabelClick({ clickedData: d });
|
||||
}
|
||||
tooltip.hide(d);
|
||||
});
|
||||
|
||||
svgGroupEl
|
||||
.selectAll("g.nodes g.node circle")
|
||||
.on("mouseenter", function (d, index, element) {
|
||||
that.activeNode = true;
|
||||
var matrix = this.getScreenCTM().translate(+this.getAttribute("cx"), +this.getAttribute("cy"));
|
||||
that.svg.selectAll(".node").classed("active", false);
|
||||
select(this).classed("active", true);
|
||||
if (that._getValueFromUser(isShowTooltip)) {
|
||||
var direction = LineageUtils.getToolTipDirection({ el: this });
|
||||
tooltip.direction(direction).show(d, this);
|
||||
}
|
||||
if (that._getValueFromUser(isShowHoverPath) === false) {
|
||||
return;
|
||||
}
|
||||
LineageUtils.onHoverFade({
|
||||
opacity: 0.3,
|
||||
mouseenter: true,
|
||||
hoveredNode: d,
|
||||
...graphOptions
|
||||
});
|
||||
})
|
||||
.on("mouseleave", function (d) {
|
||||
that.activeNode = false;
|
||||
var nodeEL = this;
|
||||
setTimeout(function (argument) {
|
||||
if (!(that.activeTip || that.activeNode)) {
|
||||
select(nodeEL).classed("active", false);
|
||||
if (that._getValueFromUser(isShowTooltip)) {
|
||||
tooltip.hide(d);
|
||||
}
|
||||
}
|
||||
}, 150);
|
||||
if (that._getValueFromUser(isShowHoverPath) === false) {
|
||||
return;
|
||||
}
|
||||
LineageUtils.onHoverFade({
|
||||
mouseenter: false,
|
||||
hoveredNode: d,
|
||||
...graphOptions
|
||||
});
|
||||
})
|
||||
.on("click", function (d) {
|
||||
if (event.defaultPrevented) return; // ignore drag
|
||||
event.preventDefault();
|
||||
tooltip.hide(d);
|
||||
svg.selectAll("g.node>circle").classed("node-detail-highlight", false);
|
||||
select(this).classed("node-detail-highlight", true);
|
||||
if (onNodeClick && typeof onNodeClick === "function") {
|
||||
onNodeClick({ clickedData: d, el: this });
|
||||
}
|
||||
});
|
||||
|
||||
// Bind event on edgePath
|
||||
var edgePathEl = svgGroupEl.selectAll("g.edgePath");
|
||||
edgePathEl.selectAll("path.path").on("click", function (d) {
|
||||
if (onPathClick && typeof onPathClick === "function") {
|
||||
var pathRelationObj = data.relations.find(function (obj) {
|
||||
if (obj.fromEntityId === d.v && obj.toEntityId === d.w) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
onPathClick({ pathRelationObj, clickedData: d });
|
||||
}
|
||||
});
|
||||
|
||||
// tooltip hover handle to fix node hover conflict
|
||||
// select("body").on("mouseover", ".d3-tip", function(el) {
|
||||
// that.activeTip = true;
|
||||
// });
|
||||
// select("body").on("mouseleave", ".d3-tip", function(el) {
|
||||
// that.activeTip = false;
|
||||
// svg.selectAll(".node").classed("active", false);
|
||||
// //tooltip.hide();
|
||||
// });
|
||||
|
||||
// Center the graph
|
||||
if (zoom !== false) {
|
||||
LineageUtils.centerNode({
|
||||
...graphOptions,
|
||||
fitToScreen,
|
||||
svgGroupEl,
|
||||
edgePathEl
|
||||
});
|
||||
}
|
||||
|
||||
// if (platform.name === "IE") {
|
||||
// LineageUtils.refreshGraphForIE({
|
||||
// edgeEl: this.$("svg .edgePath")
|
||||
// });
|
||||
// }
|
||||
|
||||
LineageUtils.dragNode({
|
||||
...graphOptions,
|
||||
edgePathEl
|
||||
});
|
||||
|
||||
if (refresh !== true) {
|
||||
this._addLegend();
|
||||
}
|
||||
|
||||
if (this.options.afterRender) {
|
||||
this.options.afterRender();
|
||||
}
|
||||
}
|
||||
_addLegend() {
|
||||
if (this.options.legends === false) {
|
||||
return;
|
||||
}
|
||||
var container = select(this.options.legendsEl || this.options.el)
|
||||
.insert("div", ":first-child")
|
||||
.classed("legends", true);
|
||||
|
||||
let span = container.append("span").style("color", "#fb4200");
|
||||
span.append("i").classed("fa fa-circle-o fa-fw", true);
|
||||
span.append("span").html("Current Entity");
|
||||
|
||||
span = container.append("span").style("color", "#686868");
|
||||
span.append("i").classed("fa fa-hourglass-half fa-fw", true);
|
||||
span.append("span").html("In Progress");
|
||||
|
||||
span = container.append("span").style("color", "#df9b00");
|
||||
span.append("i").classed("fa fa-long-arrow-right fa-fw", true);
|
||||
span.append("span").html("Lineage");
|
||||
|
||||
span = container.append("span").style("color", "#fb4200");
|
||||
span.append("i").classed("fa fa-long-arrow-right fa-fw", true);
|
||||
span.append("span").html("Impact");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// 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.
|
||||
|
||||
//fonts
|
||||
$font_0: Source Sans Pro;
|
||||
$font_1: sans-serif;
|
||||
|
||||
//Colors
|
||||
|
||||
$white: #fff;
|
||||
$dark_gray: #666;
|
||||
$light_gray: #e8e8e8;
|
||||
$black_80: rgba(0, 0, 0, 0.8);
|
||||
|
||||
$color_mountain_mist_approx: #999;
|
||||
$color_keppel_approx: #37bb9b;
|
||||
$color_suva_gray_approx: #868686;
|
||||
$color_havelock_blue_approx: #4a90e2;
|
||||
$color_celeste_approx: #ccc;
|
||||
$color_bright_turquoise_approx: #00ffd0;
|
||||
$color_jungle_green_approx: #38bb9b;
|
||||
$delete_link: #bb5838;
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
// 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.
|
||||
|
||||
/* graph.scss */
|
||||
|
||||
.node {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 10px;
|
||||
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 {
|
||||
fill: $color_suva_gray_approx;
|
||||
|
||||
&.highlight {
|
||||
cursor: pointer;
|
||||
fill: $color_havelock_blue_approx;
|
||||
text-decoration: underline;
|
||||
|
||||
tspan {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
circle {
|
||||
-moz-transition: all 0.3s;
|
||||
-webkit-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
stroke-width: 1.5px;
|
||||
|
||||
&.node-detail-highlight {
|
||||
stroke: $color_havelock_blue_approx;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
&.nodeImage {
|
||||
&.green:hover {
|
||||
stroke: #ffb203;
|
||||
}
|
||||
|
||||
&.blue:hover {
|
||||
stroke: #4b91e2;
|
||||
}
|
||||
|
||||
&.currentNode {
|
||||
stroke: #fb4200;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
-moz-transform: scale(1.4);
|
||||
-webkit-transform: scale(1.4);
|
||||
transform: scale(1.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
circle {
|
||||
-moz-transform: scale(1.4);
|
||||
-webkit-transform: scale(1.4);
|
||||
transform: scale(1.4);
|
||||
|
||||
&.nodeImage {
|
||||
&.green {
|
||||
stroke: #ffb203;
|
||||
}
|
||||
|
||||
&.blue {
|
||||
stroke: #4b91e2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.legends {
|
||||
> span {
|
||||
margin-right: 8px;
|
||||
font-family: $font_0;
|
||||
}
|
||||
}
|
||||
|
||||
svg.hover {
|
||||
g.node {
|
||||
opacity: 0.1 !important;
|
||||
}
|
||||
|
||||
g.edgePath {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
g.node.hover-active-node,
|
||||
g.edgePath.hover-active-path {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.invisible {
|
||||
.node circle {
|
||||
transition: all 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.edgePath {
|
||||
.path {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: $color_celeste_approx;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.d3-tip {
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
padding: 12px;
|
||||
background: $black_80;
|
||||
color: $white;
|
||||
z-index: 999;
|
||||
max-width: 300px; //Instead of the line below you could use @include border-radius($radius, $vertical-radius)
|
||||
border-radius: 2px;
|
||||
|
||||
.tip-inner-scroll {
|
||||
overflow: auto;
|
||||
max-height: 300px;
|
||||
h5 {
|
||||
margin: 7px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Creates a small triangle extender for the tooltip */
|
||||
&:after {
|
||||
box-sizing: border-box;
|
||||
display: inline;
|
||||
font-size: 10px;
|
||||
width: 100%;
|
||||
line-height: 1;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* Nrthward tooltips */
|
||||
&.n:after {
|
||||
content: "\25BC";
|
||||
margin: -1px 0 0 0;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Eastward tooltips */
|
||||
&.e:after {
|
||||
content: "\25C0";
|
||||
margin: -4px 0 0 0;
|
||||
top: 50%;
|
||||
left: -8px;
|
||||
}
|
||||
|
||||
/* Southward tooltips */
|
||||
&.s:after {
|
||||
content: "\25B2";
|
||||
margin: 0 0 1px 0;
|
||||
top: -8px;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Westward tooltips */
|
||||
&.w:after {
|
||||
content: "\25B6";
|
||||
margin: -4px 0 0 -1px;
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
g.type-TK > rect {
|
||||
fill: $color_bright_turquoise_approx;
|
||||
}
|
||||
|
||||
.fullscreen-mode {
|
||||
position: fixed;
|
||||
height: 100% !important;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
right: 0;
|
||||
padding: 0 !important;
|
||||
z-index: 9999;
|
||||
overflow: hidden !important;
|
||||
|
||||
.resizeGraph {
|
||||
position: fixed;
|
||||
height: 100% !important;
|
||||
|
||||
.ui-resizable-handle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.hidden-svg {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@-webkit-keyframes blink {
|
||||
from {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// 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.
|
||||
|
||||
@import "./__varibale.scss";
|
||||
@import "./graph.scss";
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
|
||||
const distPath = path.resolve(__dirname, "dist");
|
||||
|
||||
const node_env = process.env.NODE_ENV ? process.env.NODE_ENV : 'production';
|
||||
|
||||
const config = {
|
||||
mode: node_env,
|
||||
entry: "./src/index.js",
|
||||
output: {
|
||||
library: "LineageHelper",
|
||||
libraryTarget: "umd",
|
||||
path: distPath,
|
||||
filename: "index.js"
|
||||
},
|
||||
plugins: [new MiniCssExtractPlugin({ filename: "styles.css" })],
|
||||
externals: {
|
||||
//don't bundle the 'react' npm package with our bundle.js
|
||||
//but get it from a global 'React' variable
|
||||
d3: "d3",
|
||||
"dagre-d3": "dagreD3",
|
||||
platform: "platform",
|
||||
dagre: "dagre",
|
||||
graphlib: "graphlib"
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js$/,
|
||||
exclude: /(node_modules|bower_components)/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: ["@babel/preset-env"],
|
||||
plugins: ["transform-class-properties"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.s[ac]ss$/i,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
// Translates CSS into CommonJS
|
||||
"css-loader",
|
||||
// Compiles Sass to CSS
|
||||
"sass-loader"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
config.devtool = "inline-source-map";
|
||||
}
|
||||
module.exports = config;
|
||||
|
|
@ -99,10 +99,20 @@ require.config({
|
|||
'deps': ['d3'],
|
||||
'exports': ['d3-tip']
|
||||
},
|
||||
'LineageHelper': {
|
||||
'deps': ['d3'],
|
||||
},
|
||||
'dagreD3': {
|
||||
'deps': ['d3'],
|
||||
'exports': ['dagreD3']
|
||||
},
|
||||
'nvd3': {
|
||||
'deps': ['d3']
|
||||
},
|
||||
'sparkline': {
|
||||
'deps': ['jquery'],
|
||||
'exports': ['sparkline']
|
||||
},
|
||||
'pnotify': {
|
||||
'exports': ['pnotify']
|
||||
},
|
||||
|
|
@ -121,13 +131,6 @@ require.config({
|
|||
'moment': {
|
||||
'exports': ['moment']
|
||||
},
|
||||
'nvd3': {
|
||||
'deps': ['d3']
|
||||
},
|
||||
'sparkline': {
|
||||
'deps': ['jquery'],
|
||||
'exports': ['sparkline']
|
||||
},
|
||||
'jstree': {
|
||||
'deps': ['jquery']
|
||||
},
|
||||
|
|
@ -154,12 +157,15 @@ require.config({
|
|||
'asBreadcrumbs': 'libs/jquery-asBreadcrumbs/js/jquery-asBreadcrumbs.min',
|
||||
'd3': 'libs/d3/d3.min',
|
||||
'd3-tip': 'libs/d3/index',
|
||||
'LineageHelper': 'external_lib/atlas-lineage/dist/index',
|
||||
'dagreD3': 'libs/dagre-d3/dagre-d3.min',
|
||||
'nvd3': 'libs/nvd3/nv.d3.min',
|
||||
'sparkline': 'libs/sparkline/jquery.sparkline.min',
|
||||
'tmpl': 'templates',
|
||||
'requirejs.text': 'libs/requirejs-text/text',
|
||||
'handlebars': 'external_lib/require-handlebars-plugin/js/handlebars',
|
||||
'hbs': 'external_lib/require-handlebars-plugin/js/hbs',
|
||||
'i18nprecompile': 'external_lib/require-handlebars-plugin/js/i18nprecompile',
|
||||
'dagreD3': 'libs/dagre-d3/dagre-d3.min',
|
||||
'select2': 'libs/select2/select2.full.min',
|
||||
'backgrid-select-all': 'libs/backgrid-select-all/backgrid-select-all.min',
|
||||
'moment': 'libs/moment/js/moment.min',
|
||||
|
|
@ -172,8 +178,6 @@ require.config({
|
|||
'platform': 'libs/platform/platform',
|
||||
'query-builder': 'libs/jQueryQueryBuilder/js/query-builder.standalone.min',
|
||||
'daterangepicker': 'libs/bootstrap-daterangepicker/js/daterangepicker',
|
||||
'nvd3': 'libs/nvd3/nv.d3.min',
|
||||
'sparkline': 'libs/sparkline/jquery.sparkline.min',
|
||||
'table-dragger': 'libs/table-dragger/table-dragger',
|
||||
'jstree': 'libs/jstree/jstree.min',
|
||||
'jquery-steps': 'libs/jquery-steps/jquery.steps.min',
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
<li role="businessMetadata" class="tab active"><a href="#tab-businessMetadata" aria-controls="tab-businessMetadata" role="tab" data-toggle="tab">Business Metadata</a></li>
|
||||
<li role="enum"><a href="#tab-enum" aria-controls="tab-enum" role="tab" data-toggle="tab">Enumerations</a></li>
|
||||
<li role="audit"><a href="#tab-audit" aria-controls="tab-audit" role="tab" data-toggle="tab">Audits</a></li>
|
||||
<li role="typeSystem"><a href="#tab-typeSystem" aria-controls="tab-typeSystem" role="tab" data-toggle="tab">Type System</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -36,5 +37,9 @@
|
|||
<div id="r_adminTableLayoutView">
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-typeSystem" role="typeSystem" class="tab-pane animated fadeIn" style="position: relative;">
|
||||
<div id="r_typeSystemTreeLayoutView">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -100,7 +100,9 @@
|
|||
</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>
|
||||
<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>
|
||||
|
|
@ -109,11 +111,17 @@
|
|||
<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>
|
||||
<button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom In" data-id="zoom-in">
|
||||
<i class="fa fa-search-plus"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom Out" data-id="zoom-out">
|
||||
<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>
|
||||
<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">
|
||||
|
|
@ -123,7 +131,7 @@
|
|||
<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 bold-key'>
|
||||
<table class="table bold-key">
|
||||
<tbody data-id="nodeDetailTable"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -131,11 +139,7 @@
|
|||
<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"></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>
|
||||
<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 class="legends pull-left" style="height: 25px; padding: 2px;"></div>
|
||||
<div class="svg" style="height: 100%; width: 100%"></div>
|
||||
</div>
|
||||
<div class="hidden-svg"></div>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<!--
|
||||
* 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.
|
||||
-->
|
||||
<div id="typeSystemTreeViewPage" data-id="typeSystemTreeViewPage" class="systemTypeTree" style="height: calc(100vh - 180px); width: 100%; position: relative;overflow: hidden;">
|
||||
<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 bold-key">
|
||||
<tbody data-id="nodeDetailTable"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fontLoader">
|
||||
<i class="fa fa-refresh fa-spin-custom"></i>
|
||||
</div>
|
||||
<div class="box-panel filter-box">
|
||||
<div class="header clearfix">
|
||||
<h4>Filters</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="form-group text-left col-sm-12">
|
||||
<select data-id="filterServiceType"></select>
|
||||
</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="graph-button-group pull-right">
|
||||
<div>
|
||||
<button data-id="reset" class="btn btn-action btn-gray btn-sm" title="Realign Lineage">
|
||||
<i class="fa fa-retweet"></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="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" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom In" data-id="zoom-in">
|
||||
<i class="fa fa-search-plus"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom Out" data-id="zoom-out">
|
||||
<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>
|
||||
<svg class="main" width="100%" height="100%">
|
||||
</svg>
|
||||
<!-- <div id="mini" class="mini-map-type-system">
|
||||
<svg class="mini" width="100%" height="100%">
|
||||
</svg>
|
||||
</div> -->
|
||||
</div>
|
||||
|
|
@ -143,7 +143,7 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
|
|||
id = data.guid;
|
||||
}
|
||||
if (value.length > 0) {
|
||||
scope.$('td div[data-id="' + id + '"]').html('<a href="#!/detailPage/' + id + '">' + getValue(value, key) + '</a>');
|
||||
scope.$('td div[data-id="' + id + '"]').html('<a href="#!/detailPage/' + id + '">' + getValue(value) + '</a>');
|
||||
} else {
|
||||
scope.$('td div[data-id="' + id + '"]').html('<a href="#!/detailPage/' + id + '">' + _.escape(id) + '</a>');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ define(['require',
|
|||
regions: {
|
||||
RBusinessMetadataTableLayoutView: "#r_businessMetadataTableLayoutView",
|
||||
REnumTableLayoutView: '#r_enumTableLayoutView',
|
||||
RAdminTableLayoutView: '#r_adminTableLayoutView'
|
||||
RAdminTableLayoutView: '#r_adminTableLayoutView',
|
||||
RTypeSystemTreeLayoutView: '#r_typeSystemTreeLayoutView',
|
||||
|
||||
},
|
||||
|
||||
/** ui selector cache */
|
||||
|
|
@ -81,6 +83,7 @@ define(['require',
|
|||
bindEvents: function() {
|
||||
this.renderEnumLayoutView();
|
||||
this.renderAdminLayoutView();
|
||||
this.renderTypeSystemTreeLayoutView();
|
||||
},
|
||||
onRender: function() {
|
||||
this.renderBusinessMetadataLayoutView();
|
||||
|
|
@ -112,6 +115,15 @@ define(['require',
|
|||
});
|
||||
that.RAdminTableLayoutView.show(view);
|
||||
});
|
||||
},
|
||||
renderTypeSystemTreeLayoutView: function(obj) {
|
||||
var that = this;
|
||||
require(["views/graph/TypeSystemTreeView"], function(TypeSystemTreeView) {
|
||||
var view = new TypeSystemTreeView({
|
||||
entityDefCollection: that.entityDefCollection
|
||||
});
|
||||
that.RTypeSystemTreeLayoutView.show(view);
|
||||
});
|
||||
}
|
||||
});
|
||||
return AdministratorLayoutView;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ define(['require',
|
|||
'collection/VLineageList',
|
||||
'models/VEntity',
|
||||
'utils/Utils',
|
||||
'views/graph/LineageUtils',
|
||||
'LineageHelper',
|
||||
'd3',
|
||||
'dagreD3',
|
||||
'd3-tip',
|
||||
'utils/Enums',
|
||||
|
|
@ -31,7 +32,7 @@ define(['require',
|
|||
'utils/CommonViewFunction',
|
||||
'platform',
|
||||
'jquery-ui'
|
||||
], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, LineageUtils, dagreD3, d3Tip, Enums, UrlLinks, Globals, CommonViewFunction, platform) {
|
||||
], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, LineageHelper, d3, dagreD3, d3Tip, Enums, UrlLinks, Globals, CommonViewFunction, platform) {
|
||||
'use strict';
|
||||
|
||||
var LineageLayoutView = Backbone.Marionette.LayoutView.extend(
|
||||
|
|
@ -65,7 +66,9 @@ define(['require',
|
|||
showOnlyHoverPath: '[data-id="showOnlyHoverPath"]',
|
||||
showTooltip: '[data-id="showTooltip"]',
|
||||
saveSvg: '[data-id="saveSvg"]',
|
||||
resetLineage: '[data-id="resetLineage"]'
|
||||
resetLineage: '[data-id="resetLineage"]',
|
||||
onZoomIn: '[data-id="zoom-in"]',
|
||||
onZoomOut: '[data-id="zoom-out"]'
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
|
|
@ -86,6 +89,8 @@ define(['require',
|
|||
events["click " + this.ui.searchToggler] = 'onClickSearchToggler';
|
||||
events["click " + this.ui.saveSvg] = 'onClickSaveSvg';
|
||||
events["click " + this.ui.resetLineage] = 'onClickResetLineage';
|
||||
events["click " + this.ui.onZoomIn] = 'onClickZoomIn';
|
||||
events["click " + this.ui.onZoomOut] = 'onClickZoomOut';
|
||||
return events;
|
||||
},
|
||||
|
||||
|
|
@ -96,7 +101,6 @@ define(['require',
|
|||
initialize: function(options) {
|
||||
_.extend(this, _.pick(options, 'processCheck', 'guid', 'entity', 'entityName', 'entityDefCollection', 'actionCallBack', 'fetchCollection', 'attributeDefs'));
|
||||
this.collection = new VLineageList();
|
||||
this.lineageData = null;
|
||||
this.typeMap = {};
|
||||
this.apiGuid = {};
|
||||
this.edgeCall;
|
||||
|
|
@ -109,42 +113,18 @@ define(['require',
|
|||
selectedNode: ''
|
||||
}
|
||||
},
|
||||
initializeGraph: function() {
|
||||
this.g = {};
|
||||
this.g = new dagreD3.graphlib.Graph()
|
||||
.setGraph({
|
||||
nodesep: 50,
|
||||
ranksep: 90,
|
||||
rankdir: "LR",
|
||||
marginx: 20,
|
||||
marginy: 20,
|
||||
transition: function transition(selection) {
|
||||
return selection.transition().duration(500);
|
||||
}
|
||||
})
|
||||
.setDefaultEdgeLabel(function() {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
onRender: function() {
|
||||
var that = this;
|
||||
this.ui.searchToggler.prop("disabled", true);
|
||||
this.$graphButtonsEl = this.$(".graph-button-group button,select[data-id='selectDepth']")
|
||||
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();
|
||||
}
|
||||
if (this.processCheck) {
|
||||
this.hideCheckForProcess();
|
||||
}
|
||||
this.initializeGraph();
|
||||
//this.initializeGraph();
|
||||
this.ui.selectDepth.select2({
|
||||
data: _.sortBy([3, 6, 9, 12, 15, 18, 21]),
|
||||
tags: true,
|
||||
|
|
@ -175,21 +155,13 @@ define(['require',
|
|||
},
|
||||
onCheckUnwantedEntity: function(e) {
|
||||
var that = this;
|
||||
this.initializeGraph();
|
||||
//this.initializeGraph();
|
||||
if ($(e.target).data("id") === "checkHideProcess") {
|
||||
this.filterObj.isProcessHideCheck = e.target.checked;
|
||||
} else {
|
||||
this.filterObj.isDeletedEntityHideCheck = e.target.checked;
|
||||
}
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl
|
||||
});
|
||||
this.generateData(this.lineageData).then(function() {
|
||||
that.createGraph();
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl
|
||||
});
|
||||
});
|
||||
this.LineageHelperRef.refresh();
|
||||
},
|
||||
toggleBoxPanel: function(options) {
|
||||
var el = options && options.el,
|
||||
|
|
@ -201,6 +173,24 @@ define(['require',
|
|||
}
|
||||
this.$('circle.node-detail-highlight').removeClass("node-detail-highlight");
|
||||
},
|
||||
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');
|
||||
}
|
||||
},
|
||||
toggleDisableState: function(options) {
|
||||
var el = options.el,
|
||||
disabled = options.disabled;
|
||||
if (el && el.prop) {
|
||||
if (disabled) {
|
||||
el.prop("disabled", disabled);
|
||||
} else {
|
||||
el.prop("disabled", !el.prop("disabled"));
|
||||
}
|
||||
}
|
||||
},
|
||||
onClickNodeToggler: function(options) {
|
||||
this.toggleBoxPanel({ el: this.$('.lineage-node-detail'), nodeDetailToggler: true });
|
||||
},
|
||||
|
|
@ -214,17 +204,30 @@ define(['require',
|
|||
this.toggleBoxPanel({ el: this.ui.searchBox });
|
||||
},
|
||||
onSelectDepthChange: function(e, options) {
|
||||
this.initializeGraph();
|
||||
//this.initializeGraph();
|
||||
this.filterObj.depthCount = e.currentTarget.value;
|
||||
this.fetchGraphData({ queryParam: { 'depth': this.filterObj.depthCount } });
|
||||
},
|
||||
onClickResetLineage: function() {
|
||||
this.LineageHelperRef.refresh();
|
||||
},
|
||||
onClickSaveSvg: function(e, a) {
|
||||
this.LineageHelperRef.exportLineage();
|
||||
},
|
||||
onClickZoomIn: function() {
|
||||
this.LineageHelperRef.zoomIn();
|
||||
},
|
||||
onClickZoomOut: function() {
|
||||
this.LineageHelperRef.zoomOut();
|
||||
},
|
||||
fetchGraphData: function(options) {
|
||||
var that = this,
|
||||
queryParam = options && options.queryParam || {};
|
||||
this.$('.fontLoader').show();
|
||||
this.$('svg>g').hide();
|
||||
this.toggleDisableState({
|
||||
"el": that.$(".graph-button-group button,select[data-id='selectDepth']")
|
||||
"el": that.$graphButtonsEl,
|
||||
disabled: true
|
||||
});
|
||||
this.collection.getLineage(this.guid, {
|
||||
queryParam: queryParam,
|
||||
|
|
@ -232,24 +235,11 @@ define(['require',
|
|||
if (that.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
if (data.relations.length) {
|
||||
that.lineageData = $.extend(true, {}, data);
|
||||
that.generateData(that.lineageData).then(function(graphObj) {
|
||||
that.createGraph();
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl
|
||||
});
|
||||
});
|
||||
that.renderLineageTypeSearch().then(function() {
|
||||
that.ui.searchToggler.prop("disabled", false);
|
||||
});
|
||||
} else {
|
||||
that.noLineage();
|
||||
that.hideCheckForProcess();
|
||||
}
|
||||
|
||||
that.createGraph(data);
|
||||
that.renderLineageTypeSearch(data);
|
||||
},
|
||||
cust_error: function(model, response) {
|
||||
that.lineageData = [];
|
||||
that.noLineage();
|
||||
},
|
||||
complete: function() {
|
||||
|
|
@ -258,6 +248,80 @@ define(['require',
|
|||
}
|
||||
})
|
||||
},
|
||||
createGraph: function(data) {
|
||||
// if (_.isEmpty(this.g._nodes)) {
|
||||
// this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>');
|
||||
// return;
|
||||
// }
|
||||
var that = this;
|
||||
$('.resizeGraph').css("height", this.$('.svg').height() + "px");
|
||||
|
||||
this.LineageHelperRef = new LineageHelper.default({
|
||||
entityDefCollection: this.entityDefCollection.fullCollection.toJSON(),
|
||||
data: data,
|
||||
el: this.$('.svg')[0],
|
||||
legendsEl: this.$('.legends')[0],
|
||||
getFilterObj: function() {
|
||||
return {
|
||||
isProcessHideCheck: that.filterObj.isProcessHideCheck,
|
||||
isDeletedEntityHideCheck: that.filterObj.isDeletedEntityHideCheck
|
||||
}
|
||||
},
|
||||
isShowHoverPath: function() { return that.ui.showOnlyHoverPath.prop('checked') },
|
||||
isShowTooltip: function() { return that.ui.showTooltip.prop('checked') },
|
||||
onPathClick: function(d) {
|
||||
console.log("Path Clicked");
|
||||
if (d.pathRelationObj) {
|
||||
var relationshipId = d.pathRelationObj.relationshipId;
|
||||
require(['views/graph/PropagationPropertyModal'], function(PropagationPropertyModal) {
|
||||
var view = new PropagationPropertyModal({
|
||||
edgeInfo: d.pathRelationObj,
|
||||
relationshipId: relationshipId,
|
||||
lineageData: data,
|
||||
apiGuid: that.apiGuid,
|
||||
detailPageFetchCollection: that.fetchCollection
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
onNodeClick: function(d) {
|
||||
that.onClickNodeToggler();
|
||||
that.updateRelationshipDetails({ guid: d.clickedData });
|
||||
},
|
||||
onLabelClick: function(d) {
|
||||
var guid = d.clickedData;
|
||||
if (that.guid == guid) {
|
||||
Utils.notifyInfo({
|
||||
html: true,
|
||||
content: "You are already on " + "<b>" + that.entityName + "</b> detail page."
|
||||
});
|
||||
} else {
|
||||
Utils.setUrl({
|
||||
url: '#!/detailPage/' + guid + '?tabActive=lineage',
|
||||
mergeBrowserUrl: false,
|
||||
trigger: true
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeRender: function() {
|
||||
that.$('.fontLoader').show();
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl,
|
||||
disabled: true
|
||||
});
|
||||
},
|
||||
afterRender: function() {
|
||||
// Remove Loader
|
||||
that.$('.fontLoader').hide();
|
||||
if (data.relations.length) {
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl,
|
||||
disabled: false
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
noLineage: function() {
|
||||
this.$('.fontLoader').hide();
|
||||
this.$('.depth-container').hide();
|
||||
|
|
@ -269,513 +333,14 @@ define(['require',
|
|||
hideCheckForProcess: function() {
|
||||
this.$('.hideProcessContainer').hide();
|
||||
},
|
||||
isProcess: function(node) {
|
||||
var typeName = node.typeName,
|
||||
superTypes = node.superTypes,
|
||||
entityDef = node.entityDef;
|
||||
if (typeName == "Process") {
|
||||
return true;
|
||||
}
|
||||
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)
|
||||
};
|
||||
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;
|
||||
}
|
||||
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;
|
||||
},
|
||||
generateData: function(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var that = this,
|
||||
relations = options && options.relations || {},
|
||||
guidEntityMap = options && options.guidEntityMap || {},
|
||||
isHideFilterOn = this.filterObj.isProcessHideCheck || this.filterObj.isDeletedEntityHideCheck,
|
||||
newHashMap = {},
|
||||
styleObj = {
|
||||
fill: 'none',
|
||||
stroke: '#ffb203',
|
||||
width: 3
|
||||
},
|
||||
makeNodeData = function(relationObj) {
|
||||
if (relationObj) {
|
||||
if (relationObj.updatedValues) {
|
||||
return relationObj;
|
||||
}
|
||||
var obj = _.extend(relationObj, {
|
||||
shape: "img",
|
||||
updatedValues: true,
|
||||
label: relationObj.displayText.trunc(18),
|
||||
toolTipLabel: relationObj.displayText,
|
||||
id: relationObj.guid,
|
||||
isLineage: true,
|
||||
isIncomplete: relationObj.isIncomplete,
|
||||
entityDef: that.getEntityDef(relationObj.typeName)
|
||||
});
|
||||
obj["serviceType"] = that.getServiceType({ typeName: relationObj.typeName, entityDef: obj.entityDef });
|
||||
obj["superTypes"] = that.getNestedSuperTypes({ entityDef: obj.entityDef });
|
||||
obj['isProcess'] = that.isProcess(obj);
|
||||
obj['isDeleted'] = that.isDeleted(obj);
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
crateLineageRelationshipHashMap = function(data) {
|
||||
var that = this,
|
||||
relations = data && data.relations,
|
||||
newHashMap = {};
|
||||
_.each(relations, function(obj) {
|
||||
if (newHashMap[obj.fromEntityId]) {
|
||||
newHashMap[obj.fromEntityId].push(obj.toEntityId);
|
||||
} else {
|
||||
newHashMap[obj.fromEntityId] = [obj.toEntityId];
|
||||
}
|
||||
});
|
||||
return newHashMap;
|
||||
},
|
||||
getStyleObjStr = function(styleObj) {
|
||||
return 'fill:' + styleObj.fill + ';stroke:' + styleObj.stroke + ';stroke-width:' + styleObj.width;
|
||||
},
|
||||
getNewToNodeRelationship = function(toNodeGuid) {
|
||||
if (toNodeGuid && relationshipMap[toNodeGuid]) {
|
||||
var newRelationship = [];
|
||||
_.each(relationshipMap[toNodeGuid], function(guid) {
|
||||
var nodeToBeUpdated = that.isNodeToBeUpdated(makeNodeData(guidEntityMap[guid]));
|
||||
if (nodeToBeUpdated.update) {
|
||||
var newRelation = getNewToNodeRelationship(guid);
|
||||
if (newRelation) {
|
||||
newRelationship = newRelationship.concat(newRelation);
|
||||
}
|
||||
} else {
|
||||
newRelationship.push(guid);
|
||||
}
|
||||
});
|
||||
return newRelationship;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
getToNodeRelation = function(toNodes, fromNodeToBeUpdated) {
|
||||
var toNodeRelationship = [];
|
||||
_.each(toNodes, function(toNodeGuid) {
|
||||
var toNodeToBeUpdated = that.isNodeToBeUpdated(makeNodeData(guidEntityMap[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;
|
||||
},
|
||||
setNode = function(guid) {
|
||||
if (!that.g._nodes[guid]) {
|
||||
var nodeData = makeNodeData(guidEntityMap[guid]);
|
||||
that.g.setNode(guid, nodeData);
|
||||
return nodeData;
|
||||
} else {
|
||||
return that.g._nodes[guid];
|
||||
}
|
||||
},
|
||||
setEdge = function(fromNodeGuid, toNodeGuid) {
|
||||
that.g.setEdge(fromNodeGuid, toNodeGuid, {
|
||||
"arrowhead": 'arrowPoint',
|
||||
"curve": LineageUtils.BezierCurve,
|
||||
"style": getStyleObjStr(styleObj),
|
||||
"styleObj": styleObj
|
||||
});
|
||||
},
|
||||
setGraphData = function(fromEntityId, toEntityId) {
|
||||
setNode(fromEntityId);
|
||||
setNode(toEntityId);
|
||||
setEdge(fromEntityId, toEntityId);
|
||||
},
|
||||
pendingFromRelationship = {};
|
||||
if (isHideFilterOn) {
|
||||
var relationshipMap = crateLineageRelationshipHashMap(options)
|
||||
_.each(relationshipMap, function(toNodes, fromNodeGuid) {
|
||||
var fromNodeToBeUpdated = that.isNodeToBeUpdated(makeNodeData(guidEntityMap[fromNodeGuid])),
|
||||
toNodeList = getToNodeRelation(toNodes, fromNodeToBeUpdated);
|
||||
if (fromNodeToBeUpdated.update) {
|
||||
if (pendingFromRelationship[fromNodeGuid]) {
|
||||
pendingFromRelationship[fromNodeGuid] = pendingFromRelationship[fromNodeGuid].concat(toNodeList);
|
||||
} else {
|
||||
pendingFromRelationship[fromNodeGuid] = toNodeList;
|
||||
}
|
||||
} else {
|
||||
_.each(toNodeList, function(toNodeGuid) {
|
||||
setGraphData(fromNodeGuid, toNodeGuid);
|
||||
});
|
||||
}
|
||||
})
|
||||
} else {
|
||||
_.each(relations, function(obj) {
|
||||
setGraphData(obj.fromEntityId, obj.toEntityId);
|
||||
});
|
||||
}
|
||||
if (this.g._nodes[this.guid]) {
|
||||
if (this.g._nodes[this.guid]) {
|
||||
this.g._nodes[this.guid]['isLineage'] = false;
|
||||
}
|
||||
this.findImpactNodeAndUpdateData({ "guid": this.guid, "getStyleObjStr": getStyleObjStr });
|
||||
}
|
||||
resolve(this.g);
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
findImpactNodeAndUpdateData: function(options) {
|
||||
var that = this,
|
||||
guid = options.guid,
|
||||
getStyleObjStr = options.getStyleObjStr,
|
||||
traversedMap = {},
|
||||
styleObj = {
|
||||
fill: 'none',
|
||||
stroke: '#fb4200',
|
||||
width: 3
|
||||
},
|
||||
traversed = function(toNodeList, fromNodeGuid) {
|
||||
if (!_.isEmpty(toNodeList)) {
|
||||
if (!traversedMap[fromNodeGuid]) {
|
||||
traversedMap[fromNodeGuid] = true;
|
||||
_.each(toNodeList, function(val, toNodeGuid) {
|
||||
if (that.g._nodes[toNodeGuid]) {
|
||||
that.g._nodes[toNodeGuid]['isLineage'] = false;
|
||||
}
|
||||
that.g.setEdge(fromNodeGuid, toNodeGuid, {
|
||||
"arrowhead": 'arrowPoint',
|
||||
"curve": LineageUtils.BezierCurve,
|
||||
"style": getStyleObjStr(styleObj),
|
||||
'styleObj': styleObj
|
||||
});
|
||||
traversed(that.g._sucs[toNodeGuid], toNodeGuid);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
traversed(this.g._sucs[guid], guid)
|
||||
},
|
||||
zoomed: function(that) {
|
||||
this.$('svg').find('>g').attr("transform",
|
||||
"translate(" + this.zoom.translate() + ")" +
|
||||
"scale(" + this.zoom.scale() + ")"
|
||||
);
|
||||
if (platform.name === "IE") {
|
||||
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() {
|
||||
if (_.isEmpty(this.g._nodes)) {
|
||||
this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>');
|
||||
return;
|
||||
}
|
||||
var that = this,
|
||||
width = this.$('svg').width(),
|
||||
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
|
||||
if (node) {
|
||||
node.rx = node.ry = 5;
|
||||
}
|
||||
});
|
||||
// Create the renderer
|
||||
var render = new dagreD3.render();
|
||||
// Add our custom arrow (a hollow-point)
|
||||
render.arrows().arrowPoint = function(parent, id, edge, type) {
|
||||
return LineageUtils.arrowPointRender(parent, id, edge, type, { guid: that.guid, dagreD3: dagreD3 });
|
||||
};
|
||||
// Render custom img inside shape
|
||||
render.shapes().img = function(parent, bbox, node) {
|
||||
return LineageUtils.imgShapeRender(parent, bbox, node, { guid: that.guid, dagreD3: dagreD3, imageObject: imageObject, $defs: that.svg.select('defs') });
|
||||
};
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
if (this.$("svg").find('.output').length) {
|
||||
this.$("svg").find('.output').parent('g').remove();
|
||||
}
|
||||
var svg = this.svg = d3.select(this.$("svg")[0])
|
||||
.attr("viewBox", "0 0 " + width + " " + height)
|
||||
.attr("enable-background", "new 0 0 " + width + " " + height),
|
||||
svgGroup = svg.append("g");
|
||||
// Append defs
|
||||
svg.append("defs");
|
||||
var zoom = this.zoom = d3.behavior.zoom()
|
||||
.center([width / 2, height / 2])
|
||||
.scaleExtent([0.01, 50])
|
||||
.on("zoom", that.zoomed.bind(this));
|
||||
|
||||
function zoomClick() {
|
||||
var clicked = d3.event.target,
|
||||
direction = 1,
|
||||
factor = 0.5,
|
||||
target_zoom = 1,
|
||||
center = [width / 2, height / 2],
|
||||
translate = zoom.translate(),
|
||||
translate0 = [],
|
||||
l = [],
|
||||
view = { x: translate[0], y: translate[1], k: zoom.scale() };
|
||||
|
||||
d3.event.preventDefault();
|
||||
direction = (this.id === 'zoom_in') ? 1 : -1;
|
||||
target_zoom = zoom.scale() * (1 + factor * direction);
|
||||
|
||||
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];
|
||||
|
||||
view.x += center[0] - l[0];
|
||||
view.y += center[1] - l[1];
|
||||
|
||||
that.interpolateZoom([view.x, view.y], view.k, that, zoom);
|
||||
}
|
||||
d3.selectAll(this.$('.lineageZoomButton')).on('click', zoomClick);
|
||||
var tooltip = d3Tip()
|
||||
.attr('class', 'd3-tip')
|
||||
.offset([10, 0])
|
||||
.html(function(d) {
|
||||
var value = that.g.node(d);
|
||||
var htmlStr = "";
|
||||
if (value.id !== that.guid) {
|
||||
htmlStr = "<h5 style='text-align: center;'>" + (value.isLineage ? "Lineage" : "Impact") + "</h5>";
|
||||
}
|
||||
htmlStr += "<h5 class='text-center'><span style='color:#359f89'>" + value.toolTipLabel + "</span></h5> ";
|
||||
if (value.typeName) {
|
||||
htmlStr += "<h5 class='text-center'><span>(" + value.typeName + ")</span></h5> ";
|
||||
}
|
||||
if (value.queryText) {
|
||||
htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> ";
|
||||
}
|
||||
return "<div class='tip-inner-scroll'>" + htmlStr + "</div>";
|
||||
});
|
||||
|
||||
svg.call(zoom)
|
||||
.call(tooltip);
|
||||
if (platform.name !== "IE") {
|
||||
this.$('.fontLoader').hide();
|
||||
}
|
||||
render(svgGroup, this.g);
|
||||
svg.on("dblclick.zoom", null)
|
||||
// .on("wheel.zoom", null);
|
||||
//change text postion
|
||||
svgGroup.selectAll("g.nodes g.label")
|
||||
.attr("transform", "translate(2,-35)")
|
||||
.on('mouseenter', function(d) {
|
||||
d3.select(this).classed("highlight", true);
|
||||
})
|
||||
.on('mouseleave', function(d) {
|
||||
d3.select(this).classed("highlight", false);
|
||||
})
|
||||
.on('click', function(d) {
|
||||
d3.event.preventDefault();
|
||||
tooltip.hide(d);
|
||||
if (that.guid == d) {
|
||||
Utils.notifyInfo({
|
||||
html: true,
|
||||
content: "You are already on " + "<b>" + that.entityName + "</b> detail page."
|
||||
});
|
||||
} else {
|
||||
Utils.setUrl({
|
||||
url: '#!/detailPage/' + d + '?tabActive=lineage',
|
||||
mergeBrowserUrl: false,
|
||||
trigger: true
|
||||
});
|
||||
}
|
||||
});
|
||||
svgGroup.selectAll("g.nodes g.node")
|
||||
.on('mouseenter', function(d) {
|
||||
that.activeNode = true;
|
||||
var matrix = this.getScreenCTM()
|
||||
.translate(+this.getAttribute("cx"), +this.getAttribute("cy"));
|
||||
that.$('svg').find('.node').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
// Fix
|
||||
var width = $('body').width();
|
||||
var currentELWidth = $(this).offset();
|
||||
var direction = 'e';
|
||||
if (((width - currentELWidth.left) < 330)) {
|
||||
direction = (((width - currentELWidth.left) < 330) && ((currentELWidth.top) < 400)) ? 'sw' : 'w';
|
||||
if (((width - currentELWidth.left) < 330) && ((currentELWidth.top) > 600)) {
|
||||
direction = 'nw';
|
||||
}
|
||||
} else if (((currentELWidth.top) > 600)) {
|
||||
direction = (((width - currentELWidth.left) < 330) && ((currentELWidth.top) > 600)) ? 'nw' : 'n';
|
||||
if ((currentELWidth.left) < 50) {
|
||||
direction = 'ne'
|
||||
}
|
||||
} else if ((currentELWidth.top) < 400) {
|
||||
direction = ((currentELWidth.left) < 50) ? 'se' : 's';
|
||||
}
|
||||
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('mouseleave', function(d) {
|
||||
that.activeNode = false;
|
||||
var nodeEL = this;
|
||||
setTimeout(function(argument) {
|
||||
if (!(that.activeTip || that.activeNode)) {
|
||||
$(nodeEL).removeClass('active');
|
||||
if (that.ui.showTooltip.prop('checked')) {
|
||||
tooltip.hide(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
|
||||
d3.event.preventDefault();
|
||||
tooltip.hide(d);
|
||||
that.onClickNodeToggler({ obj: d });
|
||||
$(el).find('circle').addClass('node-detail-highlight');
|
||||
that.updateRelationshipDetails({ guid: d });
|
||||
});
|
||||
|
||||
svgGroup.selectAll("g.edgePath path.path").on('click', function(d) {
|
||||
var data = { obj: _.find(that.lineageData.relations, { "fromEntityId": d.v, "toEntityId": d.w }) };
|
||||
if (data.obj) {
|
||||
var 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;
|
||||
});
|
||||
$('body').on('mouseleave', '.d3-tip', function(el) {
|
||||
that.activeTip = false;
|
||||
that.$('svg').find('.node').removeClass('active');
|
||||
tooltip.hide();
|
||||
});
|
||||
|
||||
// Center the graph
|
||||
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);
|
||||
if (platform.name === "IE") {
|
||||
LineageUtils.refreshGraphForIE({
|
||||
edgeEl: this.$('svg .edgePath')
|
||||
});
|
||||
}
|
||||
LineageUtils.DragNode({
|
||||
svg: this.svg,
|
||||
g: this.g,
|
||||
guid: this.guid,
|
||||
edgeEl: this.$('svg .edgePath')
|
||||
}).init();
|
||||
},
|
||||
renderLineageTypeSearch: function() {
|
||||
renderLineageTypeSearch: function(data) {
|
||||
var that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var data = [],
|
||||
typeStr = '<option></option>';
|
||||
if (!_.isEmpty(that.lineageData)) {
|
||||
_.each(that.lineageData.guidEntityMap, function(obj, index) {
|
||||
var nodeData = that.g._nodes[obj.guid];
|
||||
var typeStr = '<option></option>';
|
||||
if (!_.isEmpty(data)) {
|
||||
_.each(data.guidEntityMap, function(obj, index) {
|
||||
var nodeData = that.LineageHelperRef.getNode(obj.guid);
|
||||
if ((that.filterObj.isProcessHideCheck || that.filterObj.isDeletedEntityHideCheck) && nodeData && (nodeData.isProcess || nodeData.isDeleted)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -799,42 +364,9 @@ define(['require',
|
|||
}).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);
|
||||
}
|
||||
}).init();
|
||||
that.svg.selectAll('.nodes g.label').attr('stroke', function(c, d) {
|
||||
if (c == selectedNode) {
|
||||
return "#316132";
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
});
|
||||
that.LineageHelperRef.searchNode({ guid: selectedNode });
|
||||
});
|
||||
if (this.searchNodeObj.selectedNode) {
|
||||
this.ui.lineageTypeSearch.val(this.searchNodeObj.selectedNode);
|
||||
|
|
@ -844,8 +376,11 @@ define(['require',
|
|||
updateRelationshipDetails: function(options) {
|
||||
var that = this,
|
||||
guid = options.guid,
|
||||
initialData = that.g._nodes[guid],
|
||||
typeName = initialData.typeName || guid,
|
||||
initialData = that.LineageHelperRef.getNode(guid);
|
||||
if (initialData === undefined) {
|
||||
return;
|
||||
}
|
||||
var typeName = initialData.typeName || guid,
|
||||
attributeDefs = initialData && initialData.entityDef ? initialData.entityDef.attributeDefs : null;
|
||||
this.$("[data-id='typeName']").text(typeName);
|
||||
this.entityModel = new VEntity({});
|
||||
|
|
@ -876,46 +411,6 @@ define(['require',
|
|||
"attributeDefs": attributeDefs,
|
||||
"sortBy": false
|
||||
}));
|
||||
},
|
||||
onClickSaveSvg: function(e, a) {
|
||||
var that = this,
|
||||
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.
|
||||
}
|
||||
this.toggleLoader(loaderTargetDiv);
|
||||
Utils.notifyInfo({
|
||||
content: "Lineage will be downloaded in a moment."
|
||||
});
|
||||
var entityAttributes = that.entity && that.entity.attributes;
|
||||
LineageUtils.SaveSvg(e, {
|
||||
svg: that.$('svg')[0],
|
||||
svgWidth: that.$('svg').width(),
|
||||
svgHeight: that.$('svg').height(),
|
||||
toggleLoader: function() {
|
||||
that.toggleLoader(loaderTargetDiv);
|
||||
},
|
||||
downloadFileName: ((entityAttributes && (entityAttributes.qualifiedName || entityAttributes.name) || "lineage_export") + ".png")
|
||||
})
|
||||
},
|
||||
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"));
|
||||
}
|
||||
}
|
||||
});
|
||||
return LineageLayoutView;
|
||||
|
|
|
|||
|
|
@ -1,524 +0,0 @@
|
|||
/**
|
||||
* 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'], function(require, Utils) {
|
||||
'use strict';
|
||||
var LineageUtils = {};
|
||||
LineageUtils.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 + ')');
|
||||
}
|
||||
}
|
||||
});
|
||||
LineageUtils.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
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
LineageUtils.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);
|
||||
});
|
||||
}
|
||||
LineageUtils.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);
|
||||
});
|
||||
}
|
||||
LineageUtils.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] });
|
||||
if (platform.name === "IE") {
|
||||
LineageUtils.refreshGraphForIE({ "edgeEl": edgePathEl })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LineageUtils.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;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
LineageUtils.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;
|
||||
}
|
||||
LineageUtils.imgShapeRender = function(parent, bbox, node, viewOptions) {
|
||||
var LineageUtilsRef = this,
|
||||
imageIconPath = Utils.getEntityIconPath({ entityData: node }),
|
||||
imgName = imageIconPath.split("/").pop(),
|
||||
viewGuid = viewOptions.guid,
|
||||
dagreD3 = viewOptions.dagreD3,
|
||||
imageObject = viewOptions.imageObject,
|
||||
$defs = viewOptions.$defs;
|
||||
if (node.isDeleted) {
|
||||
imgName = "deleted_" + imgName;
|
||||
}
|
||||
if (node.id == viewGuid) {
|
||||
var currentNode = true
|
||||
}
|
||||
var shapeSvg = parent.append('circle')
|
||||
.attr('fill', 'url(#img_' + imgName + ')')
|
||||
.attr('r', '24px')
|
||||
.attr('data-stroke', node.id)
|
||||
.attr('stroke-width', "2px")
|
||||
.attr("class", "nodeImage " + (currentNode ? "currentNode" : (node.isProcess ? "process" : "node")));
|
||||
if (currentNode) {
|
||||
shapeSvg.attr("stroke", "#fb4200")
|
||||
}
|
||||
|
||||
if ($defs.select('pattern[id="img_' + imgName + '"]').empty()) {
|
||||
var $pattern = $defs.append("pattern")
|
||||
.attr("x", "0%")
|
||||
.attr("y", "0%")
|
||||
.attr("patternUnits", "objectBoundingBox")
|
||||
.attr("id", "img_" + imgName)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.append('image')
|
||||
.attr("href", function(d) {
|
||||
var that = this;
|
||||
if (node) {
|
||||
var getImageData = function(options) {
|
||||
var imagePath = options.imagePath,
|
||||
ajaxOptions = {
|
||||
"url": imagePath,
|
||||
"method": "get",
|
||||
"cache": true
|
||||
}
|
||||
|
||||
if (platform.name !== "IE") {
|
||||
ajaxOptions["mimeType"] = "text/plain; charset=x-user-defined";
|
||||
}
|
||||
shapeSvg.attr("data-iconpath", imagePath);
|
||||
$.ajax(ajaxOptions)
|
||||
.always(function(data, status, xhr) {
|
||||
if (data.status == 404) {
|
||||
getImageData({
|
||||
"imagePath": Utils.getEntityIconPath({ entityData: node, errorUrl: imagePath })
|
||||
});
|
||||
} else if (data) {
|
||||
if (platform.name !== "IE") {
|
||||
imageObject[imageIconPath] = 'data:image/png;base64,' + LineageUtilsRef.base64Encode({ "data": data });
|
||||
} else {
|
||||
imageObject[imageIconPath] = imagePath;
|
||||
}
|
||||
d3.select(that).attr("xlink:href", imageObject[imageIconPath]);
|
||||
if (imageIconPath !== shapeSvg.attr("data-iconpath")) {
|
||||
shapeSvg.attr("data-iconpathorigin", imageIconPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
getImageData({
|
||||
"imagePath": imageIconPath
|
||||
});
|
||||
}
|
||||
})
|
||||
.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);
|
||||
};
|
||||
return shapeSvg;
|
||||
}
|
||||
LineageUtils.arrowPointRender = function(parent, id, edge, type, viewOptions) {
|
||||
var node = parent.node(),
|
||||
parentNode = node ? node.parentNode : parent,
|
||||
dagreD3 = viewOptions.dagreD3;
|
||||
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")
|
||||
.attr("refX", 8)
|
||||
.attr("refY", 5)
|
||||
.attr("markerUnits", "strokeWidth")
|
||||
.attr("markerWidth", 4)
|
||||
.attr("markerHeight", 4)
|
||||
.attr("orient", "auto");
|
||||
|
||||
var path = marker.append("path")
|
||||
.attr("d", "M 0 0 L 10 5 L 0 10 z")
|
||||
.style("fill", edge.styleObj.stroke);
|
||||
dagreD3.util.applyStyle(path, edge[type + "Style"]);
|
||||
}
|
||||
LineageUtils.BezierCurve = function(context) {
|
||||
return {
|
||||
lineStart: function() {
|
||||
this.data = [];
|
||||
},
|
||||
point: function(x, y) {
|
||||
this.data.push([x, y]);
|
||||
},
|
||||
lineEnd: function() {
|
||||
var x0 = this.data[0][0],
|
||||
y0 = this.data[0][1],
|
||||
cp1x = this.data[1][0],
|
||||
cp1y = this.data[1][1],
|
||||
cp2Obj = this.data[this.data.length - 2],
|
||||
cp2x = cp2Obj[0],
|
||||
cp2y = cp2Obj[1],
|
||||
axisObj = this.data[this.data.length - 1],
|
||||
x1 = axisObj[0],
|
||||
y1 = axisObj[1];
|
||||
context.moveTo(x0, y0);
|
||||
context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x1, y1);
|
||||
}
|
||||
}
|
||||
}
|
||||
LineageUtils.SaveSvg = function(e, viewOptions) {
|
||||
var that = this,
|
||||
svg = viewOptions.svg,
|
||||
svgWidth = viewOptions.svgWidth,
|
||||
svgHeight = viewOptions.svgHeight,
|
||||
downloadFileName = viewOptions.downloadFileName,
|
||||
toggleLoader = viewOptions.toggleLoader,
|
||||
svgClone = svg.cloneNode(true),
|
||||
scaleFactor = 1;
|
||||
setTimeout(function() {
|
||||
if (platform.name === "Firefox") {
|
||||
svgClone.setAttribute('width', svgWidth);
|
||||
svgClone.setAttribute('height', svgHeight);
|
||||
}
|
||||
$('.hidden-svg').html(svgClone);
|
||||
$(svgClone).find('>g').attr("transform", "scale(" + scaleFactor + ")");
|
||||
$(svgClone).find("foreignObject").remove();
|
||||
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");
|
||||
a.download = downloadFileName;
|
||||
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!"
|
||||
});
|
||||
toggleLoader();
|
||||
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();
|
||||
toggleLoader();
|
||||
if (platform.name === 'Safari') {
|
||||
that.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!"
|
||||
});
|
||||
toggleLoader();
|
||||
}
|
||||
|
||||
};
|
||||
img.src = url;
|
||||
}, 0);
|
||||
}
|
||||
return LineageUtils;
|
||||
});
|
||||
|
|
@ -147,7 +147,7 @@ define(['require',
|
|||
|
||||
onRender: function() {},
|
||||
updateEdgeView: function(options) {
|
||||
var obj = options.obj,
|
||||
var obj = options,
|
||||
fromEntity = this.lineageData.guidEntityMap[obj.fromEntityId],
|
||||
toEntity = this.lineageData.guidEntityMap[obj.toEntityId];
|
||||
if (fromEntity && toEntity) {
|
||||
|
|
@ -183,9 +183,9 @@ define(['require',
|
|||
that.ui.propagationOptions.find('.both').show();
|
||||
} else {
|
||||
that.ui.propagationOptions.find('.both').hide();
|
||||
if (that.edgeInfo.obj.fromEntityId != relationshipObj.end1.guid && relationshipObj.propagateTags == "ONE_TO_TWO") {
|
||||
if (that.edgeInfo.fromEntityId != relationshipObj.end1.guid && relationshipObj.propagateTags == "ONE_TO_TWO") {
|
||||
isTwoToOne = true;
|
||||
} else if (that.edgeInfo.obj.fromEntityId == relationshipObj.end1.guid && relationshipObj.propagateTags == "TWO_TO_ONE") {
|
||||
} else if (that.edgeInfo.fromEntityId == relationshipObj.end1.guid && relationshipObj.propagateTags == "TWO_TO_ONE") {
|
||||
isTwoToOne = true;
|
||||
}
|
||||
if (isTwoToOne) {
|
||||
|
|
@ -241,7 +241,7 @@ define(['require',
|
|||
relationshipProp = {
|
||||
"propagateTags": that.getPropagationFlow({
|
||||
"relationshipData": _.extend({}, this.apiGuid[entityId].relationship, { 'propagateTags': PropagationValue }),
|
||||
"graphData": { from: { guid: this.edgeInfo.obj.fromEntityId } }
|
||||
"graphData": { from: { guid: this.edgeInfo.fromEntityId } }
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -16,24 +16,26 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
define(['require',
|
||||
'backbone',
|
||||
'hbs!tmpl/graph/RelationshipLayoutView_tmpl',
|
||||
'collection/VLineageList',
|
||||
'models/VEntity',
|
||||
'utils/Utils',
|
||||
'utils/CommonViewFunction',
|
||||
'd3-tip',
|
||||
'utils/Enums',
|
||||
'utils/UrlLinks',
|
||||
'platform'
|
||||
], function(require, Backbone, RelationshipLayoutViewtmpl, VLineageList, VEntity, Utils, CommonViewFunction, d3Tip, Enums, UrlLinks, platform) {
|
||||
'use strict';
|
||||
define([
|
||||
"require",
|
||||
"backbone",
|
||||
"hbs!tmpl/graph/RelationshipLayoutView_tmpl",
|
||||
"collection/VLineageList",
|
||||
"models/VEntity",
|
||||
"utils/Utils",
|
||||
"utils/CommonViewFunction",
|
||||
"d3",
|
||||
"d3-tip",
|
||||
"utils/Enums",
|
||||
"utils/UrlLinks",
|
||||
"platform"
|
||||
], function(require, Backbone, RelationshipLayoutViewtmpl, VLineageList, VEntity, Utils, CommonViewFunction, d3, d3Tip, Enums, UrlLinks, platform) {
|
||||
"use strict";
|
||||
|
||||
var RelationshipLayoutView = Backbone.Marionette.LayoutView.extend(
|
||||
/** @lends RelationshipLayoutView */
|
||||
{
|
||||
_viewName: 'RelationshipLayoutView',
|
||||
_viewName: "RelationshipLayoutView",
|
||||
|
||||
template: RelationshipLayoutViewtmpl,
|
||||
className: "resizeGraph",
|
||||
|
|
@ -59,15 +61,15 @@ define(['require',
|
|||
events["click " + this.ui.relationshipDetailClose] = function() {
|
||||
this.toggleInformationSlider({ close: true });
|
||||
};
|
||||
events["keyup " + this.ui.searchNode] = 'searchNode';
|
||||
events["click " + this.ui.boxClose] = 'toggleBoxPanel';
|
||||
events["keyup " + this.ui.searchNode] = "searchNode";
|
||||
events["click " + this.ui.boxClose] = "toggleBoxPanel";
|
||||
events["change " + this.ui.relationshipViewToggle] = function(e) {
|
||||
this.relationshipViewToggle(e.currentTarget.checked)
|
||||
this.relationshipViewToggle(e.currentTarget.checked);
|
||||
};
|
||||
events["click " + this.ui.noValueToggle] = function(e) {
|
||||
Utils.togglePropertyRelationshipTableEmptyValues({
|
||||
"inputType": this.ui.noValueToggle,
|
||||
"tableEl": this.ui.relationshipDetailValue
|
||||
inputType: this.ui.noValueToggle,
|
||||
tableEl: this.ui.relationshipDetailValue
|
||||
});
|
||||
};
|
||||
return events;
|
||||
|
|
@ -78,7 +80,7 @@ define(['require',
|
|||
* @constructs
|
||||
*/
|
||||
initialize: function(options) {
|
||||
_.extend(this, _.pick(options, 'entity', 'entityName', 'guid', 'actionCallBack', 'attributeDefs'));
|
||||
_.extend(this, _.pick(options, "entity", "entityName", "guid", "actionCallBack", "attributeDefs"));
|
||||
this.graphData = this.createData(this.entity);
|
||||
},
|
||||
createData: function(entity) {
|
||||
|
|
@ -89,14 +91,14 @@ define(['require',
|
|||
_.each(entity.relationshipAttributes, function(obj, key) {
|
||||
if (!_.isEmpty(obj)) {
|
||||
links.push({
|
||||
"source": nodes[that.entity.typeName] ||
|
||||
(nodes[that.entity.typeName] = _.extend({ "name": that.entity.typeName }, { value: entity })),
|
||||
"target": nodes[key] ||
|
||||
source: nodes[that.entity.typeName] ||
|
||||
(nodes[that.entity.typeName] = _.extend({ name: that.entity.typeName }, { value: entity })),
|
||||
target: nodes[key] ||
|
||||
(nodes[key] = _.extend({
|
||||
"name": key
|
||||
name: key
|
||||
}, { value: obj })),
|
||||
"value": obj
|
||||
})
|
||||
value: obj
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -104,7 +106,7 @@ define(['require',
|
|||
},
|
||||
onRender: function() {
|
||||
this.ui.zoomControl.hide();
|
||||
this.$el.addClass('auto-height');
|
||||
this.$el.addClass("auto-height");
|
||||
},
|
||||
onShow: function(argument) {
|
||||
if (this.graphData && _.isEmpty(this.graphData.links)) {
|
||||
|
|
@ -115,29 +117,29 @@ define(['require',
|
|||
this.createTable();
|
||||
},
|
||||
noRelationship: function() {
|
||||
this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relationship data found</text>');
|
||||
this.$("svg").html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relationship data found</text>');
|
||||
},
|
||||
toggleInformationSlider: function(options) {
|
||||
if (options.open && !this.$('.relationship-details').hasClass("open")) {
|
||||
this.$('.relationship-details').addClass('open');
|
||||
} else if (options.close && this.$('.relationship-details').hasClass("open")) {
|
||||
d3.selectAll('circle').attr("stroke", "none");
|
||||
this.$('.relationship-details').removeClass('open');
|
||||
if (options.open && !this.$(".relationship-details").hasClass("open")) {
|
||||
this.$(".relationship-details").addClass("open");
|
||||
} else if (options.close && this.$(".relationship-details").hasClass("open")) {
|
||||
d3.selectAll("circle").attr("stroke", "none");
|
||||
this.$(".relationship-details").removeClass("open");
|
||||
}
|
||||
},
|
||||
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');
|
||||
this.$el.find(".show-box-panel").removeClass("show-box-panel");
|
||||
if (el && el.addClass) {
|
||||
el.addClass('show-box-panel');
|
||||
el.addClass("show-box-panel");
|
||||
}
|
||||
this.$('circle.node-detail-highlight').removeClass("node-detail-highlight");
|
||||
this.$("circle.node-detail-highlight").removeClass("node-detail-highlight");
|
||||
},
|
||||
searchNode: function(e) {
|
||||
var $el = $(e.currentTarget);
|
||||
this.updateRelationshipDetails(_.extend({}, $el.data(), { searchString: $el.val() }))
|
||||
this.updateRelationshipDetails(_.extend({}, $el.data(), { searchString: $el.val() }));
|
||||
},
|
||||
updateRelationshipDetails: function(options) {
|
||||
var data = options.obj.value,
|
||||
|
|
@ -147,10 +149,10 @@ define(['require',
|
|||
getEntityTypelist = function(options) {
|
||||
var activeEntityColor = "#4a90e2",
|
||||
deletedEntityColor = "#BB5838",
|
||||
entityTypeHtml = '<pre>',
|
||||
entityTypeHtml = "<pre>",
|
||||
getdefault = function(obj) {
|
||||
var options = obj.options,
|
||||
status = (Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : ''),
|
||||
status = Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : "",
|
||||
guid = options.guid,
|
||||
entityColor = obj.color,
|
||||
name = obj.name,
|
||||
|
|
@ -167,7 +169,7 @@ define(['require',
|
|||
},
|
||||
getWithButton = function(obj) {
|
||||
var options = obj.options,
|
||||
status = (Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : ''),
|
||||
status = Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : "",
|
||||
guid = options.guid,
|
||||
entityColor = obj.color,
|
||||
name = obj.name,
|
||||
|
|
@ -178,7 +180,7 @@ define(['require',
|
|||
title = "Deleted";
|
||||
if (relationship) {
|
||||
icon = '<i class="fa fa-long-arrow-right"></i>';
|
||||
status = (Enums.entityStateReadOnly[options.relationshipStatus || options.status] ? "deleted-relation" : '');
|
||||
status = Enums.entityStateReadOnly[options.relationshipStatus || options.status] ? "deleted-relation" : "";
|
||||
title = "Relationship Deleted";
|
||||
}
|
||||
return "<li class=" + status + ">" +
|
||||
|
|
@ -191,33 +193,33 @@ define(['require',
|
|||
if (options.entityStatus == "ACTIVE") {
|
||||
if (options.relationshipStatus == "ACTIVE") {
|
||||
entityTypeHtml = getdefault({
|
||||
"color": activeEntityColor,
|
||||
"options": options,
|
||||
"name": name
|
||||
color: activeEntityColor,
|
||||
options: options,
|
||||
name: name
|
||||
});
|
||||
} else if (options.relationshipStatus == "DELETED") {
|
||||
entityTypeHtml = getWithButton({
|
||||
"color": activeEntityColor,
|
||||
"options": options,
|
||||
"name": name,
|
||||
"relationship": true
|
||||
})
|
||||
color: activeEntityColor,
|
||||
options: options,
|
||||
name: name,
|
||||
relationship: true
|
||||
});
|
||||
}
|
||||
} else if (options.entityStatus == "DELETED") {
|
||||
entityTypeHtml = getWithButton({
|
||||
"color": deletedEntityColor,
|
||||
"options": options,
|
||||
"name": name,
|
||||
"entity": true
|
||||
})
|
||||
color: deletedEntityColor,
|
||||
options: options,
|
||||
name: name,
|
||||
entity: true
|
||||
});
|
||||
} else {
|
||||
entityTypeHtml = getdefault({
|
||||
"color": activeEntityColor,
|
||||
"options": options,
|
||||
"name": name
|
||||
color: activeEntityColor,
|
||||
options: options,
|
||||
name: name
|
||||
});
|
||||
}
|
||||
return entityTypeHtml + '</pre>';
|
||||
return entityTypeHtml + "</pre>";
|
||||
};
|
||||
this.ui.searchNode.hide();
|
||||
this.$("[data-id='typeName']").text(typeName);
|
||||
|
|
@ -225,7 +227,7 @@ define(['require',
|
|||
var name = options.entityName ? options.entityName : Utils.getName(options, "displayText");
|
||||
var entityTypeButton = getEntityTypelist(options);
|
||||
return entityTypeButton;
|
||||
}
|
||||
};
|
||||
if (_.isArray(data)) {
|
||||
if (data.length > 1) {
|
||||
this.ui.searchNode.show();
|
||||
|
|
@ -249,121 +251,248 @@ define(['require',
|
|||
this.$("[data-id='entityList']").html(listString);
|
||||
},
|
||||
createGraph: function(data) {
|
||||
var that = this,
|
||||
width = this.$('svg').width(),
|
||||
height = this.$('svg').height();
|
||||
//Ref - http://bl.ocks.org/fancellu/2c782394602a93921faff74e594d1bb1
|
||||
|
||||
var scale = 1.0,
|
||||
activeEntityColor = "#00b98b",
|
||||
var that = this,
|
||||
width = this.$("svg").width(),
|
||||
height = this.$("svg").height(),
|
||||
nodes = d3.values(data.nodes),
|
||||
links = data.links;
|
||||
|
||||
var activeEntityColor = "#00b98b",
|
||||
deletedEntityColor = "#BB5838",
|
||||
defaultEntityColor = "#e0e0e0",
|
||||
selectedNodeColor = "#4a90e2";
|
||||
|
||||
var force = d3.layout.force()
|
||||
.nodes(d3.values(data.nodes))
|
||||
.links(data.links)
|
||||
.size([width, height])
|
||||
.linkDistance(200)
|
||||
.gravity(0.5)
|
||||
.friction(0.1)
|
||||
.charge(function(d) {
|
||||
var charge = -2000;
|
||||
if (d.index === 0) charge = 100
|
||||
return charge;
|
||||
})
|
||||
.on("tick", tick)
|
||||
.start();
|
||||
|
||||
var zoom = d3.behavior.zoom()
|
||||
.scale(scale)
|
||||
.scaleExtent([1, 5])
|
||||
.on("zoom", zoomed);
|
||||
|
||||
function zoomed() {
|
||||
container.attr("transform",
|
||||
"translate(" + zoom.translate() + ")" +
|
||||
"scale(" + zoom.scale() + ")"
|
||||
);
|
||||
}
|
||||
|
||||
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));
|
||||
zoomed();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function zoomClick() {
|
||||
var clicked = d3.event.target,
|
||||
direction = 1,
|
||||
factor = 0.5,
|
||||
target_zoom = 1,
|
||||
center = [width / 2, height / 2],
|
||||
extent = zoom.scaleExtent(),
|
||||
translate = zoom.translate(),
|
||||
translate0 = [],
|
||||
l = [],
|
||||
view = { x: translate[0], y: translate[1], k: zoom.scale() };
|
||||
|
||||
d3.event.preventDefault();
|
||||
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];
|
||||
|
||||
view.x += center[0] - l[0];
|
||||
view.y += center[1] - l[1];
|
||||
|
||||
interpolateZoom([view.x, view.y], view.k);
|
||||
}
|
||||
|
||||
|
||||
|
||||
d3.selectAll(this.$('.lineageZoomButton')).on('click', zoomClick);
|
||||
|
||||
var svg = d3.select(this.$("svg")[0])
|
||||
var svg = d3
|
||||
.select(this.$("svg")[0])
|
||||
.attr("viewBox", "0 0 " + width + " " + height)
|
||||
.attr("enable-background", "new 0 0 " + width + " " + height)
|
||||
.call(zoom)
|
||||
.on("dblclick.zoom", null),
|
||||
drag = force.drag()
|
||||
.on("dragstart", dragstart);
|
||||
.attr("enable-background", "new 0 0 " + width + " " + height),
|
||||
node,
|
||||
path;
|
||||
|
||||
var container = svg.append("g")
|
||||
var container = svg
|
||||
.append("g")
|
||||
.attr("id", "container")
|
||||
.attr("transform", "translate(0,0)scale(1,1)");
|
||||
|
||||
|
||||
// build the arrow.
|
||||
container.append("svg:defs").selectAll("marker")
|
||||
.data(["deletedLink", "activeLink"]) // Different link/path types can be defined here
|
||||
.enter().append("svg:marker") // This section adds in the arrows
|
||||
.attr("id", String)
|
||||
.attr("viewBox", "0 -5 10 10")
|
||||
.attr("refX", 10)
|
||||
.attr("refY", -0.5)
|
||||
.attr("markerWidth", 6)
|
||||
.attr("markerHeight", 6)
|
||||
.attr("orient", "auto")
|
||||
.append("svg:path")
|
||||
.attr("d", "M0,-5L10,0L0,5")
|
||||
.attr("fill", function(d) {
|
||||
return d == "deletedLink" ? deletedEntityColor : activeEntityColor;
|
||||
var zoom = d3
|
||||
.zoom()
|
||||
.scaleExtent([0.1, 4])
|
||||
.on("zoom", function() {
|
||||
container.attr("transform", d3.event.transform);
|
||||
});
|
||||
|
||||
svg.call(zoom).on("dblclick.zoom", null);
|
||||
|
||||
container
|
||||
.append("svg:defs")
|
||||
.selectAll("marker")
|
||||
.data(["deletedLink", "activeLink"]) // Different link/path types can be defined here
|
||||
.enter()
|
||||
.append("svg:marker") // This section adds in the arrows
|
||||
.attr("id", String)
|
||||
.attr("viewBox", "-0 -5 10 10")
|
||||
.attr("refX", 10)
|
||||
.attr("refY", -0.5)
|
||||
.attr("orient", "auto")
|
||||
.attr("markerWidth", 6)
|
||||
.attr("markerHeight", 6)
|
||||
.append("svg:path")
|
||||
.attr("d", "M 0,-5 L 10 ,0 L 0,5")
|
||||
.attr("fill", function(d) {
|
||||
return d == "deletedLink" ? deletedEntityColor : activeEntityColor;
|
||||
})
|
||||
.style("stroke", "none");
|
||||
|
||||
var forceLink = d3
|
||||
.forceLink()
|
||||
.id(function(d) {
|
||||
return d.id;
|
||||
})
|
||||
.distance(function(d) {
|
||||
return 100;
|
||||
})
|
||||
.strength(1);
|
||||
|
||||
var simulation = d3
|
||||
.forceSimulation()
|
||||
.force("link", forceLink)
|
||||
.force("charge", d3.forceManyBody())
|
||||
.force("center", d3.forceCenter(width / 2, height / 2));
|
||||
|
||||
update();
|
||||
|
||||
function update() {
|
||||
path = container
|
||||
.append("svg:g")
|
||||
.selectAll("path")
|
||||
.data(links)
|
||||
.enter()
|
||||
.append("svg:path")
|
||||
.attr("class", "relatioship-link")
|
||||
.attr("stroke", function(d) {
|
||||
return getPathColor({ data: d, type: "path" });
|
||||
})
|
||||
.attr("marker-end", function(d) {
|
||||
return "url(#" + (isAllEntityRelationDeleted({ data: d }) ? "deletedLink" : "activeLink") + ")";
|
||||
});
|
||||
|
||||
node = container
|
||||
.selectAll(".node")
|
||||
.data(nodes)
|
||||
.enter()
|
||||
.append("g")
|
||||
.attr("class", "node")
|
||||
.on("mousedown", function() {
|
||||
console.log(d3.event);
|
||||
d3.event.preventDefault();
|
||||
})
|
||||
.on("click", function(d) {
|
||||
if (d3.event.defaultPrevented) return; // ignore drag
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
that.ui.boxClose.trigger("click");
|
||||
return;
|
||||
}
|
||||
that.toggleBoxPanel({ el: that.$(".relationship-node-details") });
|
||||
that.ui.searchNode.data({ obj: d });
|
||||
$(this)
|
||||
.find("circle")
|
||||
.addClass("node-detail-highlight");
|
||||
that.updateRelationshipDetails({ obj: d });
|
||||
})
|
||||
.call(
|
||||
d3
|
||||
.drag()
|
||||
.on("start", dragstarted)
|
||||
.on("drag", dragged)
|
||||
);
|
||||
|
||||
var circleContainer = node.append("g");
|
||||
|
||||
circleContainer
|
||||
.append("circle")
|
||||
.attr("cx", 0)
|
||||
.attr("cy", 0)
|
||||
.attr("r", function(d) {
|
||||
d.radius = 25;
|
||||
return d.radius;
|
||||
})
|
||||
.attr("fill", function(d) {
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
if (isAllEntityRelationDeleted({ data: d, type: "node" })) {
|
||||
return deletedEntityColor;
|
||||
} else {
|
||||
return selectedNodeColor;
|
||||
}
|
||||
} else if (isAllEntityRelationDeleted({ data: d, type: "node" })) {
|
||||
return deletedEntityColor;
|
||||
} else {
|
||||
return activeEntityColor;
|
||||
}
|
||||
})
|
||||
.attr("typename", function(d) {
|
||||
return d.name;
|
||||
});
|
||||
|
||||
circleContainer
|
||||
.append("text")
|
||||
.attr("x", 0)
|
||||
.attr("y", 0)
|
||||
.attr("dy", 25 - 17)
|
||||
.attr("text-anchor", "middle")
|
||||
.style("font-family", "FontAwesome")
|
||||
.style("font-size", function(d) {
|
||||
return "25px";
|
||||
})
|
||||
.text(function(d) {
|
||||
var iconObj = Enums.graphIcon[d.name];
|
||||
if (iconObj && iconObj.textContent) {
|
||||
return iconObj.textContent;
|
||||
} else {
|
||||
if (d && _.isArray(d.value) && d.value.length > 1) {
|
||||
return "\uf0c5";
|
||||
} else {
|
||||
return "\uf016";
|
||||
}
|
||||
}
|
||||
})
|
||||
.attr("fill", function(d) {
|
||||
return "#fff";
|
||||
});
|
||||
|
||||
var countBox = circleContainer.append("g");
|
||||
|
||||
countBox
|
||||
.append("circle")
|
||||
.attr("cx", 18)
|
||||
.attr("cy", -20)
|
||||
.attr("r", function(d) {
|
||||
if (_.isArray(d.value) && d.value.length > 1) {
|
||||
return 10;
|
||||
}
|
||||
});
|
||||
|
||||
countBox
|
||||
.append("text")
|
||||
.attr("dx", 18)
|
||||
.attr("dy", -16)
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("fill", defaultEntityColor)
|
||||
.text(function(d) {
|
||||
if (_.isArray(d.value) && d.value.length > 1) {
|
||||
return d.value.length;
|
||||
}
|
||||
});
|
||||
|
||||
node.append("text")
|
||||
.attr("x", -15)
|
||||
.attr("y", "35")
|
||||
.text(function(d) {
|
||||
return d.name;
|
||||
});
|
||||
|
||||
simulation.nodes(nodes).on("tick", ticked);
|
||||
|
||||
simulation.force("link").links(links);
|
||||
}
|
||||
|
||||
function ticked() {
|
||||
path.attr("d", function(d) {
|
||||
var diffX = d.target.x - d.source.x,
|
||||
diffY = d.target.y - d.source.y,
|
||||
// Length of path from center of source node to center of target node
|
||||
pathLength = Math.sqrt(diffX * diffX + diffY * diffY),
|
||||
// x and y distances from center to outside edge of target node
|
||||
offsetX = (diffX * d.target.radius) / pathLength,
|
||||
offsetY = (diffY * d.target.radius) / pathLength;
|
||||
|
||||
return "M" + d.source.x + "," + d.source.y + "A" + pathLength + "," + pathLength + " 0 0,1 " + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
|
||||
});
|
||||
|
||||
node.attr("transform", function(d) {
|
||||
return "translate(" + d.x + "," + d.y + ")";
|
||||
});
|
||||
}
|
||||
|
||||
function dragstarted(d) {
|
||||
d3.event.sourceEvent.stopPropagation();
|
||||
if (d && d.value && d.value.guid != that.guid) {
|
||||
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
|
||||
d.fx = d.x;
|
||||
d.fy = d.y;
|
||||
}
|
||||
}
|
||||
|
||||
function dragged(d) {
|
||||
if (d && d.value && d.value.guid != that.guid) {
|
||||
d.fx = d3.event.x;
|
||||
d.fy = d3.event.y;
|
||||
}
|
||||
}
|
||||
|
||||
function getPathColor(options) {
|
||||
return isAllEntityRelationDeleted(options) ? deletedEntityColor : activeEntityColor
|
||||
return isAllEntityRelationDeleted(options) ? deletedEntityColor : activeEntityColor;
|
||||
}
|
||||
|
||||
function isAllEntityRelationDeleted(options) {
|
||||
|
|
@ -374,193 +503,52 @@ define(['require',
|
|||
d.value = [d.value];
|
||||
}
|
||||
|
||||
return (_.findIndex(d.value, function(val) {
|
||||
if (type == "node") {
|
||||
return (val.entityStatus || val.status) == "ACTIVE"
|
||||
} else {
|
||||
return val.relationshipStatus == "ACTIVE"
|
||||
}
|
||||
}) == -1);
|
||||
return (
|
||||
_.findIndex(d.value, function(val) {
|
||||
if (type == "node") {
|
||||
return (val.entityStatus || val.status) == "ACTIVE";
|
||||
} else {
|
||||
return val.relationshipStatus == "ACTIVE";
|
||||
}
|
||||
}) == -1
|
||||
);
|
||||
}
|
||||
|
||||
// add the links and the arrows
|
||||
var path = container.append("svg:g").selectAll("path")
|
||||
.data(force.links())
|
||||
.enter().append("svg:path")
|
||||
// .attr("class", function(d) { return "link " + d.type; })
|
||||
.attr("class", "relatioship-link")
|
||||
.attr("stroke", function(d) { return getPathColor({ data: d, type: 'path' }) })
|
||||
.attr("marker-end", function(d) {
|
||||
return "url(#" + (isAllEntityRelationDeleted({ data: d }) ? "deletedLink" : "activeLink") + ")";
|
||||
});
|
||||
|
||||
// define the nodes
|
||||
var node = container.selectAll(".node")
|
||||
.data(force.nodes())
|
||||
.enter().append("g")
|
||||
.attr("class", "node")
|
||||
.on('touchstart', function(d) {
|
||||
if (d && d.value && d.value.guid != that.guid) {
|
||||
d3.event.stopPropagation();
|
||||
}
|
||||
})
|
||||
.on('mousedown', function(d) {
|
||||
if (d && d.value && d.value.guid != that.guid) {
|
||||
d3.event.stopPropagation();
|
||||
}
|
||||
})
|
||||
.on('click', function(d) {
|
||||
if (d3.event.defaultPrevented) return; // ignore drag
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
that.ui.boxClose.trigger('click');
|
||||
return;
|
||||
}
|
||||
that.toggleBoxPanel({ el: that.$('.relationship-node-details') });
|
||||
that.ui.searchNode.data({ obj: d });
|
||||
$(this).find('circle').addClass("node-detail-highlight");
|
||||
that.updateRelationshipDetails({ obj: d });
|
||||
|
||||
}).call(force.drag);
|
||||
|
||||
// add the nodes
|
||||
var circleContainer = node.append("g");
|
||||
circleContainer.on("dblclick", function(d) {
|
||||
if ((_.isArray(d.value) && d.value.length == 1) || d.value.guid) {
|
||||
var guid = _.isArray(d.value) ? _.first(d.value).guid : d.value.guid;
|
||||
Utils.setUrl({
|
||||
url: '#!/detailPage/' + guid,
|
||||
mergeBrowserUrl: false,
|
||||
urlParams: { tabActive: 'relationship' },
|
||||
trigger: true
|
||||
});
|
||||
var zoomClick = function() {
|
||||
var scaleFactor = 0.8;
|
||||
if (this.id === 'zoom_in') {
|
||||
scaleFactor = 1.3;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
circleContainer.append("circle")
|
||||
.attr("cx", 0)
|
||||
.attr("cy", 0)
|
||||
.attr("r", function(d) {
|
||||
d.radius = 25;
|
||||
return d.radius;
|
||||
})
|
||||
.attr("fill", function(d) {
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
if (isAllEntityRelationDeleted({ data: d, type: 'node' })) {
|
||||
return deletedEntityColor;
|
||||
} else {
|
||||
return selectedNodeColor;
|
||||
}
|
||||
} else if (isAllEntityRelationDeleted({ data: d, type: 'node' })) {
|
||||
return deletedEntityColor;
|
||||
} else {
|
||||
return activeEntityColor;
|
||||
}
|
||||
})
|
||||
.attr("typename", function(d) {
|
||||
return d.name;
|
||||
})
|
||||
circleContainer.append("text")
|
||||
.attr('x', 0)
|
||||
.attr('y', 0)
|
||||
.attr('dy', (25 - 17))
|
||||
.attr("text-anchor", "middle")
|
||||
.style("font-family", "FontAwesome")
|
||||
.style('font-size', function(d) { return '25px'; })
|
||||
.text(function(d) {
|
||||
var iconObj = Enums.graphIcon[d.name];
|
||||
if (iconObj && iconObj.textContent) {
|
||||
return iconObj.textContent;
|
||||
} else {
|
||||
if (d && _.isArray(d.value) && d.value.length > 1) {
|
||||
return '\uf0c5';
|
||||
} else {
|
||||
return '\uf016';
|
||||
}
|
||||
}
|
||||
})
|
||||
.attr("fill", function(d) {
|
||||
return "#fff";
|
||||
});
|
||||
var countBox = circleContainer.append('g')
|
||||
countBox.append("circle")
|
||||
.attr("cx", 18)
|
||||
.attr("cy", -20)
|
||||
.attr("r", function(d) {
|
||||
if (_.isArray(d.value) && d.value.length > 1) {
|
||||
return 10;
|
||||
}
|
||||
});
|
||||
|
||||
countBox.append("text")
|
||||
.attr('dx', 18)
|
||||
.attr('dy', -16)
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("fill", defaultEntityColor)
|
||||
.text(function(d) {
|
||||
if (_.isArray(d.value) && d.value.length > 1) {
|
||||
return d.value.length;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// add the text
|
||||
node.append("text")
|
||||
.attr("x", -15)
|
||||
.attr("y", "35")
|
||||
.text(function(d) { return d.name; });
|
||||
|
||||
// add the curvy lines
|
||||
function tick() {
|
||||
path.attr("d", function(d) {
|
||||
var diffX = d.target.x - d.source.x,
|
||||
diffY = d.target.y - d.source.y,
|
||||
|
||||
// Length of path from center of source node to center of target node
|
||||
pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY)),
|
||||
|
||||
// x and y distances from center to outside edge of target node
|
||||
offsetX = (diffX * d.target.radius) / pathLength,
|
||||
offsetY = (diffY * d.target.radius) / pathLength;
|
||||
|
||||
return "M" + d.source.x + "," + d.source.y + "A" + pathLength + "," + pathLength + " 0 0,1 " + (d.target.x - offsetX) + "," + (d.target.y - offsetY)
|
||||
});
|
||||
|
||||
node.attr("transform", function(d) {
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
d.x = (width / 2)
|
||||
d.y = (height / 2)
|
||||
}
|
||||
return "translate(" + d.x + "," + d.y + ")";
|
||||
});
|
||||
zoom.scaleBy(svg.transition().duration(750), scaleFactor);
|
||||
}
|
||||
|
||||
function dragstart(d) {
|
||||
d3.select(this).classed("fixed", d.fixed = true);
|
||||
}
|
||||
d3.selectAll(this.$('.lineageZoomButton')).on('click', zoomClick);
|
||||
},
|
||||
createTable: function() {
|
||||
this.entityModel = new VEntity({});
|
||||
var table = CommonViewFunction.propertyTable({ scope: this, valueObject: this.entity.relationshipAttributes, attributeDefs: this.attributeDefs });
|
||||
var table = CommonViewFunction.propertyTable({
|
||||
scope: this,
|
||||
valueObject: this.entity.relationshipAttributes,
|
||||
attributeDefs: this.attributeDefs
|
||||
});
|
||||
this.ui.relationshipDetailValue.html(table);
|
||||
Utils.togglePropertyRelationshipTableEmptyValues({
|
||||
"inputType": this.ui.noValueToggle,
|
||||
"tableEl": this.ui.relationshipDetailValue
|
||||
inputType: this.ui.noValueToggle,
|
||||
tableEl: this.ui.relationshipDetailValue
|
||||
});
|
||||
},
|
||||
relationshipViewToggle: function(checked) {
|
||||
this.ui.relationshipDetailTable.toggleClass('visible invisible');
|
||||
this.ui.relationshipSVG.toggleClass('visible invisible');
|
||||
this.ui.relationshipDetailTable.toggleClass("visible invisible");
|
||||
this.ui.relationshipSVG.toggleClass("visible invisible");
|
||||
|
||||
if (checked) {
|
||||
this.ui.zoomControl.hide();
|
||||
this.$el.addClass('auto-height');
|
||||
this.$el.addClass("auto-height");
|
||||
} else {
|
||||
this.ui.zoomControl.show();
|
||||
this.$el.removeClass('auto-height');
|
||||
this.$el.removeClass("auto-height");
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
return RelationshipLayoutView;
|
||||
});
|
||||
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
* 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",
|
||||
"backbone",
|
||||
"hbs!tmpl/graph/TypeSystemTreeView_tmpl",
|
||||
"collection/VLineageList",
|
||||
"models/VEntity",
|
||||
"LineageHelper",
|
||||
"d3",
|
||||
"dagreD3",
|
||||
"d3-tip",
|
||||
"utils/CommonViewFunction",
|
||||
"utils/Utils",
|
||||
"platform",
|
||||
"jquery-ui"
|
||||
], function(require, Backbone, TypeSystemTreeViewTmpl, VLineageList, VEntity, LineageHelper, d3, dagreD3, d3Tip, CommonViewFunction, Utils, platform) {
|
||||
"use strict";
|
||||
|
||||
/** @lends TypeSystemTreeView */
|
||||
var TypeSystemTreeView = Backbone.Marionette.LayoutView.extend({
|
||||
_viewName: "TypeSystemTreeViewTmpl",
|
||||
|
||||
template: TypeSystemTreeViewTmpl,
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
modalID: this.viewId,
|
||||
width: "100%",
|
||||
height: "300px"
|
||||
};
|
||||
},
|
||||
|
||||
/** Layout sub regions */
|
||||
regions: {
|
||||
RTypeSystemTreeViewPage: "#r_typeSystemTreeViewPage"
|
||||
},
|
||||
|
||||
/** ui selector cache */
|
||||
ui: {
|
||||
typeSystemTreeViewPage: "[data-id='typeSystemTreeViewPage']",
|
||||
boxClose: '[data-id="box-close"]',
|
||||
nodeDetailTable: '[data-id="nodeDetailTable"]',
|
||||
typeSearch: '[data-id="typeSearch"]',
|
||||
filterServiceType: '[data-id="filterServiceType"]',
|
||||
onZoomIn: '[data-id="zoom-in"]',
|
||||
onZoomOut: '[data-id="zoom-out"]',
|
||||
filterBox: ".filter-box",
|
||||
searchBox: ".search-box",
|
||||
filterToggler: '[data-id="filter-toggler"]',
|
||||
searchToggler: '[data-id="search-toggler"]',
|
||||
reset: '[data-id="reset"]',
|
||||
fullscreenToggler: '[data-id="fullScreen-toggler"]'
|
||||
},
|
||||
/** ui events hash */
|
||||
events: function() {
|
||||
var events = {};
|
||||
events["click " + this.ui.boxClose] = "toggleBoxPanel";
|
||||
events["click " + this.ui.onZoomIn] = "onClickZoomIn";
|
||||
events["click " + this.ui.onZoomOut] = "onClickZoomOut";
|
||||
events["click " + this.ui.filterToggler] = "onClickFilterToggler";
|
||||
events["click " + this.ui.searchToggler] = "onClickSearchToggler";
|
||||
events["click " + this.ui.fullscreenToggler] = "onClickFullscreenToggler";
|
||||
events["click " + this.ui.reset] = "onClickReset";
|
||||
return events;
|
||||
},
|
||||
|
||||
/**
|
||||
* @constructs
|
||||
*/
|
||||
initialize: function(options) {
|
||||
_.extend(this, _.pick(options, "entityDefCollection"));
|
||||
},
|
||||
onShow: function() {
|
||||
this.$(".fontLoader").show();
|
||||
this.initializeGraph();
|
||||
this.fetchGraphData();
|
||||
},
|
||||
onRender: function() {},
|
||||
fetchGraphData: function(options) {
|
||||
var that = this;
|
||||
var entityTypeDef = that.entityDefCollection.fullCollection.toJSON();
|
||||
this.$(".fontLoader").show();
|
||||
this.$("svg").empty();
|
||||
if (that.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
if (entityTypeDef.length) {
|
||||
that.generateData($.extend(true, {}, { data: entityTypeDef }, options)).then(function(graphObj) {
|
||||
that.createGraph();
|
||||
});
|
||||
}
|
||||
},
|
||||
generateData: function(options) {
|
||||
return new Promise(
|
||||
function(resolve, reject) {
|
||||
try {
|
||||
var that = this,
|
||||
newHashMap = {},
|
||||
styleObj = {
|
||||
fill: "none",
|
||||
stroke: "#ffb203",
|
||||
width: 3
|
||||
},
|
||||
makeNodeData = function(relationObj) {
|
||||
if (relationObj) {
|
||||
if (relationObj.updatedValues) {
|
||||
return relationObj;
|
||||
}
|
||||
var obj = _.extend(relationObj, {
|
||||
shape: "img",
|
||||
updatedValues: true,
|
||||
label: relationObj.name.trunc(18),
|
||||
toolTipLabel: relationObj.name,
|
||||
id: relationObj.guid,
|
||||
isLineage: true,
|
||||
isIncomplete: false
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
getStyleObjStr = function(styleObj) {
|
||||
return "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width;
|
||||
},
|
||||
setNode = function(guid, obj) {
|
||||
var node = that.LineageHelperRef.getNode(guid);
|
||||
if (!node) {
|
||||
var nodeData = makeNodeData(obj);
|
||||
that.LineageHelperRef.setNode(guid, nodeData);
|
||||
return nodeData;
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
},
|
||||
setEdge = function(fromNodeGuid, toNodeGuid) {
|
||||
that.LineageHelperRef.setEdge(fromNodeGuid, toNodeGuid, {
|
||||
arrowhead: "arrowPoint",
|
||||
style: getStyleObjStr(styleObj),
|
||||
styleObj: styleObj
|
||||
});
|
||||
},
|
||||
setGraphData = function(fromEntityId, toEntityId) {
|
||||
setNode(fromEntityId);
|
||||
setNode(toEntityId);
|
||||
setEdge(fromEntityId, toEntityId);
|
||||
};
|
||||
|
||||
if (options.data) {
|
||||
if (options.filter) {
|
||||
var pendingSubList = {},
|
||||
pendingSuperList = {},
|
||||
temp = {},
|
||||
doneList = {},
|
||||
traveseSubSuper = function(obj, ignoreSubTypes) {
|
||||
var fromEntityId = obj.guid;
|
||||
if (!ignoreSubTypes && obj.subTypes.length) {
|
||||
_.each(obj.subTypes, function(subType) {
|
||||
var tempObj = doneList[subType] || temp[subType];
|
||||
if (tempObj) {
|
||||
setNode(tempObj.guid, tempObj);
|
||||
setEdge(fromEntityId, tempObj.guid);
|
||||
} else {
|
||||
if (pendingSubList[subType]) {
|
||||
pendingSubList[subType].push(fromEntityId);
|
||||
} else {
|
||||
pendingSubList[subType] = [fromEntityId];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (obj.superTypes.length) {
|
||||
_.each(obj.superTypes, function(superType) {
|
||||
var tempObj = doneList[superType] || temp[superType];
|
||||
if (tempObj) {
|
||||
setNode(tempObj.guid, tempObj);
|
||||
setEdge(tempObj.guid, fromEntityId);
|
||||
if (tempObj.superTypes.length) {
|
||||
traveseSubSuper(tempObj, true);
|
||||
}
|
||||
} else {
|
||||
if (pendingSuperList[superType]) {
|
||||
pendingSuperList[superType].push(fromEntityId);
|
||||
} else {
|
||||
pendingSuperList[superType] = [fromEntityId];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
_.each(options.data, function(obj) {
|
||||
var fromEntityId = obj.guid;
|
||||
if (obj.serviceType === options.filter) {
|
||||
doneList[obj.name] = obj;
|
||||
setNode(fromEntityId, obj);
|
||||
if (pendingSubList[obj.name]) {
|
||||
_.map(pendingSubList[obj.name], function(guid) {
|
||||
setEdge(guid, fromEntityId);
|
||||
});
|
||||
delete pendingSubList[obj.name];
|
||||
}
|
||||
if (pendingSuperList[obj.name]) {
|
||||
_.map(pendingSuperList[obj.name], function(guid) {
|
||||
setEdge(fromEntityId, guid);
|
||||
});
|
||||
delete pendingSuperList[obj.name];
|
||||
}
|
||||
traveseSubSuper(obj);
|
||||
} else {
|
||||
if (pendingSubList[obj.name]) {
|
||||
setNode(fromEntityId, obj);
|
||||
doneList[obj.name] = obj;
|
||||
_.map(pendingSubList[obj.name], function(guid) {
|
||||
setEdge(guid, fromEntityId);
|
||||
});
|
||||
delete pendingSubList[obj.name];
|
||||
}
|
||||
if (pendingSuperList[obj.name]) {
|
||||
var fromEntityId = obj.guid;
|
||||
setNode(fromEntityId, obj);
|
||||
doneList[obj.name] = obj;
|
||||
_.map(pendingSuperList[obj.name], function(guid) {
|
||||
setEdge(fromEntityId, guid);
|
||||
});
|
||||
delete pendingSuperList[obj.name];
|
||||
}
|
||||
if (!doneList[obj.name]) {
|
||||
temp[obj.name] = obj;
|
||||
}
|
||||
}
|
||||
});
|
||||
pendingSubList = null;
|
||||
pendingSuperList = null;
|
||||
doneList = null;
|
||||
} else {
|
||||
var pendingList = {},
|
||||
doneList = {};
|
||||
|
||||
_.each(options.data, function(obj) {
|
||||
var fromEntityId = obj.guid;
|
||||
doneList[obj.name] = obj;
|
||||
setNode(fromEntityId, obj);
|
||||
if (pendingList[obj.name]) {
|
||||
_.map(pendingList[obj.name], function(guid) {
|
||||
setEdge(guid, fromEntityId);
|
||||
});
|
||||
delete pendingList[obj.name];
|
||||
}
|
||||
if (obj.subTypes.length) {
|
||||
_.each(obj.subTypes, function(subTypes) {
|
||||
//var subTypesObj = _.find(options.data({ name: superTypes });
|
||||
//setNode(superTypeObj.attributes.guid, superTypeObj.attributes);
|
||||
if (doneList[subTypes]) {
|
||||
setEdge(fromEntityId, doneList[subTypes].guid);
|
||||
} else {
|
||||
if (pendingList[subTypes]) {
|
||||
pendingList[subTypes].push(fromEntityId);
|
||||
} else {
|
||||
pendingList[subTypes] = [fromEntityId];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
pendingList = null;
|
||||
doneList = null;
|
||||
}
|
||||
}
|
||||
resolve(this.g);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
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 });
|
||||
},
|
||||
onClickZoomIn: function() {
|
||||
this.LineageHelperRef.zoomIn();
|
||||
},
|
||||
onClickZoomOut: function() {
|
||||
this.LineageHelperRef.zoomOut();
|
||||
},
|
||||
onClickFilterToggler: function() {
|
||||
this.toggleBoxPanel({ el: this.ui.filterBox });
|
||||
},
|
||||
onClickSearchToggler: function() {
|
||||
this.toggleBoxPanel({ el: this.ui.searchBox });
|
||||
},
|
||||
onClickReset: function() {
|
||||
this.fetchGraphData({ refresh: true });
|
||||
},
|
||||
onClickFullscreenToggler: function(e) {
|
||||
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");
|
||||
},
|
||||
updateDetails: function(data) {
|
||||
this.$("[data-id='typeName']").text(Utils.getName(data));
|
||||
delete data.id;
|
||||
//atttributes
|
||||
data["atttributes"] = (data.attributeDefs || []).map(function(obj) {
|
||||
return obj.name;
|
||||
});
|
||||
delete data.attributeDefs;
|
||||
//businessAttributes
|
||||
data["businessAttributes"] = _.keys(data.businessAttributeDefs);
|
||||
delete data.businessAttributeDefs;
|
||||
//relationshipAttributes
|
||||
data["relationshipAttributes"] = (data.relationshipAttributeDefs || []).map(function(obj) {
|
||||
return obj.name;
|
||||
});
|
||||
delete data.relationshipAttributeDefs;
|
||||
|
||||
console.log(data);
|
||||
|
||||
this.ui.nodeDetailTable.html(
|
||||
CommonViewFunction.propertyTable({
|
||||
scope: this,
|
||||
guidHyperLink: false,
|
||||
getEmptyString: function(key) {
|
||||
if (key === "subTypes" || key === "superTypes" || key === "atttributes" || key === "relationshipAttributes") {
|
||||
return "[]";
|
||||
}
|
||||
return "N/A";
|
||||
},
|
||||
valueObject: _.omit(data, ["isLineage", "isIncomplete", "label", "shape", "toolTipLabel", "updatedValues"]),
|
||||
sortBy: true
|
||||
})
|
||||
);
|
||||
},
|
||||
createGraph: function(refresh) {
|
||||
this.LineageHelperRef.createGraph();
|
||||
},
|
||||
filterData: function(value) {
|
||||
this.LineageHelperRef.refresh();
|
||||
this.fetchGraphData({ filter: value });
|
||||
},
|
||||
initializeGraph: function() {
|
||||
//ref - https://bl.ocks.org/seemantk/80613e25e9804934608ac42440562168
|
||||
var that = this,
|
||||
node = this.$("svg.main").parent()[0].getBoundingClientRect();
|
||||
this.$("svg").attr("viewBox", "0 0 " + node.width + " " + node.height);
|
||||
this.LineageHelperRef = new LineageHelper.default({
|
||||
el: this.$("svg.main")[0],
|
||||
legends: false,
|
||||
setDataManually: true,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
isShowHoverPath: true,
|
||||
zoom: true,
|
||||
fitToScreen: true,
|
||||
dagreOptions: {
|
||||
rankdir: "tb"
|
||||
},
|
||||
onNodeClick: function(d) {
|
||||
that.onClickNodeToggler();
|
||||
that.updateDetails(that.LineageHelperRef.getNode(d.clickedData, true));
|
||||
},
|
||||
beforeRender: function() {
|
||||
that.$(".fontLoader").show();
|
||||
},
|
||||
afterRender: function() {
|
||||
that.graphOptions = that.LineageHelperRef.getGraphOptions();
|
||||
that.renderTypeFilterSearch();
|
||||
that.$(".fontLoader").hide();
|
||||
return;
|
||||
}
|
||||
});
|
||||
},
|
||||
renderTypeFilterSearch: function(data) {
|
||||
var that = this;
|
||||
var searchStr = "<option></option>",
|
||||
filterStr = "<option></option>",
|
||||
tempFilteMap = {};
|
||||
var nodes = that.LineageHelperRef.getNodes();
|
||||
if (!_.isEmpty(nodes)) {
|
||||
_.each(nodes, function(obj) {
|
||||
searchStr += '<option value="' + obj.guid + '">' + obj.name + "</option>";
|
||||
if (obj.serviceType && !tempFilteMap[obj.serviceType]) {
|
||||
tempFilteMap[obj.serviceType] = obj.serviceType;
|
||||
filterStr += '<option value="' + obj.serviceType + '">' + obj.serviceType + "</option>";
|
||||
}
|
||||
});
|
||||
}
|
||||
this.ui.typeSearch.html(searchStr);
|
||||
if (!this.ui.filterServiceType.data("select2")) {
|
||||
this.ui.filterServiceType.html(filterStr);
|
||||
}
|
||||
|
||||
this.initilizeTypeFilterSearch();
|
||||
},
|
||||
initilizeTypeFilterSearch: function() {
|
||||
var that = this;
|
||||
this.ui.typeSearch
|
||||
.select2({
|
||||
closeOnSelect: true,
|
||||
placeholder: "Select Node"
|
||||
})
|
||||
.on("change.select2", function(e) {
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
var selectedNode = $('[data-id="typeSearch"]').val();
|
||||
//that.searchNodeObj.selectedNode = selectedNode;
|
||||
that.LineageHelperRef.searchNode({ guid: selectedNode });
|
||||
});
|
||||
if (!this.ui.filterServiceType.data("select2")) {
|
||||
this.ui.filterServiceType
|
||||
.select2({
|
||||
closeOnSelect: true,
|
||||
placeholder: "Select ServiceType"
|
||||
})
|
||||
.on("change.select2", function(e) {
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
var selectedNode = $('[data-id="filterServiceType"]').val();
|
||||
that.filterData(selectedNode);
|
||||
//that.searchNodeObj.selectedNode = selectedNode;
|
||||
//that.LineageHelperRef.searchNode({ guid: selectedNode });
|
||||
});
|
||||
// if (this.searchNodeObj.selectedNode) {
|
||||
// this.ui.typeSearch.val(this.searchNodeObj.selectedNode);
|
||||
// this.ui.typeSearch.trigger("change.select2");
|
||||
// }
|
||||
}
|
||||
}
|
||||
});
|
||||
return TypeSystemTreeView;
|
||||
});
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# 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.
|
||||
|
||||
.DS_Store
|
||||
.bower-*/
|
||||
.idea/
|
||||
node_modules/
|
||||
public/js/libs/
|
||||
dist
|
||||
target/
|
||||
*.log
|
||||
*.tgz
|
||||
node/
|
||||
.npmrc
|
||||
dist/
|
||||
!public/js/external_lib/atlas-lineage/dist
|
||||
|
|
@ -94,7 +94,7 @@ module.exports = function(grunt) {
|
|||
'backgrid-sizeable-columns.js': { 'backgrid-sizeable-columns': 'backgrid-sizeable-columns/js' },
|
||||
'Backgrid.ColumnManager.js': { 'backgrid-columnmanager/src': 'backgrid-columnmanager/js' },
|
||||
'jquery-asBreadcrumbs.min.js': { 'jquery-asBreadcrumbs/dist': 'jquery-asBreadcrumbs/js' },
|
||||
'd3.min.js': { 'd3': 'd3' },
|
||||
'd3.min.js': { 'd3/dist': 'd3' },
|
||||
'index.js': { 'd3-tip': 'd3/' },
|
||||
'dagre-d3.min.js': { 'dagre-d3/dist': 'dagre-d3' },
|
||||
'select2.full.min.js': { 'select2/dist/js': 'select2' },
|
||||
|
|
@ -223,7 +223,7 @@ module.exports = function(grunt) {
|
|||
build: {
|
||||
expand: true,
|
||||
cwd: modulesPath,
|
||||
src: ['**', '!**/scss/**', "!index.html.tpl"],
|
||||
src: ['**', '!**/scss/**', "!**/atlas-lineage/**", "**/atlas-lineage/dist/**", "!index.html.tpl"],
|
||||
dest: distPath
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@
|
|||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
|
||||
"integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
|
||||
"version": "6.12.4",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
|
||||
"integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
|
|
@ -179,9 +179,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
|
||||
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==",
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
|
||||
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-runtime": {
|
||||
|
|
@ -512,12 +512,9 @@
|
|||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
|
||||
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
|
||||
"requires": {
|
||||
"graceful-readlink": ">= 1.0.0"
|
||||
}
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
|
|
@ -620,9 +617,42 @@
|
|||
"integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU="
|
||||
},
|
||||
"d3": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz",
|
||||
"integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g="
|
||||
"version": "5.14.2",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-5.14.2.tgz",
|
||||
"integrity": "sha512-Ccipa9XrYW5N0QkP6u0Qb8kU6WekIXBiDenmZm1zLvuq/9pBBhRCJLCICEOsH5Og4B0Xw02bhqGkK5VN/oPH0w==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-axis": "1",
|
||||
"d3-brush": "1",
|
||||
"d3-chord": "1",
|
||||
"d3-collection": "1",
|
||||
"d3-color": "1",
|
||||
"d3-contour": "1",
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
"d3-dsv": "1",
|
||||
"d3-ease": "1",
|
||||
"d3-fetch": "1",
|
||||
"d3-force": "1",
|
||||
"d3-format": "1",
|
||||
"d3-geo": "1",
|
||||
"d3-hierarchy": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-path": "1",
|
||||
"d3-polygon": "1",
|
||||
"d3-quadtree": "1",
|
||||
"d3-random": "1",
|
||||
"d3-scale": "2",
|
||||
"d3-scale-chromatic": "1",
|
||||
"d3-selection": "1",
|
||||
"d3-shape": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2",
|
||||
"d3-timer": "1",
|
||||
"d3-transition": "1",
|
||||
"d3-voronoi": "1",
|
||||
"d3-zoom": "1"
|
||||
}
|
||||
},
|
||||
"d3-array": {
|
||||
"version": "1.2.4",
|
||||
|
|
@ -635,9 +665,9 @@
|
|||
"integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
|
||||
},
|
||||
"d3-brush": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.5.tgz",
|
||||
"integrity": "sha512-rEaJ5gHlgLxXugWjIkolTA0OyMvw8UWU1imYXy1v642XyyswmI1ybKOv05Ft+ewq+TFmdliD3VuK0pRp1VT/5A==",
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz",
|
||||
"integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==",
|
||||
"requires": {
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
|
|
@ -661,9 +691,9 @@
|
|||
"integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
|
||||
},
|
||||
"d3-color": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz",
|
||||
"integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg=="
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
|
||||
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
|
||||
},
|
||||
"d3-contour": {
|
||||
"version": "1.3.2",
|
||||
|
|
@ -698,14 +728,14 @@
|
|||
}
|
||||
},
|
||||
"d3-ease": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.6.tgz",
|
||||
"integrity": "sha512-SZ/lVU7LRXafqp7XtIcBdxnWl8yyLpgOmzAk0mWBI9gXNzLDx5ybZgnRbH9dN/yY5tzVBqCQ9avltSnqVwessQ=="
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz",
|
||||
"integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ=="
|
||||
},
|
||||
"d3-fetch": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.2.tgz",
|
||||
"integrity": "sha512-S2loaQCV/ZeyTyIF2oP8D1K9Z4QizUzW7cWeAOAS4U88qOt3Ucf6GsmgthuYSdyB2HyEm4CeGvkQxWsmInsIVA==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz",
|
||||
"integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==",
|
||||
"requires": {
|
||||
"d3-dsv": "1"
|
||||
}
|
||||
|
|
@ -722,14 +752,14 @@
|
|||
}
|
||||
},
|
||||
"d3-format": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.4.tgz",
|
||||
"integrity": "sha512-TWks25e7t8/cqctxCmxpUuzZN11QxIA7YrMbram94zMQ0PXjE4LVIMe/f6a4+xxL8HQ3OsAFULOINQi1pE62Aw=="
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
|
||||
"integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
|
||||
},
|
||||
"d3-geo": {
|
||||
"version": "1.11.9",
|
||||
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.11.9.tgz",
|
||||
"integrity": "sha512-9edcH6J3s/Aa3KJITWqFJbyB/8q3mMlA9Fi7z6yy+FAYMnRaxmC7jBhUnsINxVWD14GmqX3DK8uk7nV6/Ekt4A==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz",
|
||||
"integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==",
|
||||
"requires": {
|
||||
"d3-array": "1"
|
||||
}
|
||||
|
|
@ -790,9 +820,9 @@
|
|||
}
|
||||
},
|
||||
"d3-selection": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.1.tgz",
|
||||
"integrity": "sha512-BTIbRjv/m5rcVTfBs4AMBLKs4x8XaaLkwm28KWu9S2vKNqXkXt2AH2Qf0sdPZHjFxcWg/YL53zcqAz+3g4/7PA=="
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
|
||||
"integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
|
||||
},
|
||||
"d3-shape": {
|
||||
"version": "1.3.7",
|
||||
|
|
@ -808,9 +838,9 @@
|
|||
"integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
|
||||
},
|
||||
"d3-time-format": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.2.3.tgz",
|
||||
"integrity": "sha512-RAHNnD8+XvC4Zc4d2A56Uw0yJoM7bsvOlJR33bclxq399Rak/b9bhvu/InjxdWhPtkgU53JJcleJTGkNRnN6IA==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
|
||||
"integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
|
||||
"requires": {
|
||||
"d3-time": "1"
|
||||
}
|
||||
|
|
@ -826,6 +856,13 @@
|
|||
"integrity": "sha1-5bRJGuiYP95kbqSQCP9UKgM8Ciw=",
|
||||
"requires": {
|
||||
"d3": "^3.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": {
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz",
|
||||
"integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g="
|
||||
}
|
||||
}
|
||||
},
|
||||
"d3-transition": {
|
||||
|
|
@ -876,46 +913,6 @@
|
|||
"dagre": "^0.8.5",
|
||||
"graphlib": "^2.1.8",
|
||||
"lodash": "^4.17.15"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3": {
|
||||
"version": "5.15.1",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-5.15.1.tgz",
|
||||
"integrity": "sha512-Xu9gT6Lm0jH3wWJJSRomFwqnGGi3YAfWIfxNFl4++YVgYOjo3F8V2idAG3nJBgpZOkD0/RHPZX6F4k6tzgOvYw==",
|
||||
"requires": {
|
||||
"d3-array": "1",
|
||||
"d3-axis": "1",
|
||||
"d3-brush": "1",
|
||||
"d3-chord": "1",
|
||||
"d3-collection": "1",
|
||||
"d3-color": "1",
|
||||
"d3-contour": "1",
|
||||
"d3-dispatch": "1",
|
||||
"d3-drag": "1",
|
||||
"d3-dsv": "1",
|
||||
"d3-ease": "1",
|
||||
"d3-fetch": "1",
|
||||
"d3-force": "1",
|
||||
"d3-format": "1",
|
||||
"d3-geo": "1",
|
||||
"d3-hierarchy": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-path": "1",
|
||||
"d3-polygon": "1",
|
||||
"d3-quadtree": "1",
|
||||
"d3-random": "1",
|
||||
"d3-scale": "2",
|
||||
"d3-scale-chromatic": "1",
|
||||
"d3-selection": "1",
|
||||
"d3-shape": "1",
|
||||
"d3-time": "1",
|
||||
"d3-time-format": "2",
|
||||
"d3-timer": "1",
|
||||
"d3-transition": "1",
|
||||
"d3-voronoi": "1",
|
||||
"d3-zoom": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashdash": {
|
||||
|
|
@ -1108,9 +1105,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
|
||||
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
|
|
@ -1312,13 +1309,13 @@
|
|||
}
|
||||
},
|
||||
"globule": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz",
|
||||
"integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
|
||||
"integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "~7.1.1",
|
||||
"lodash": "~4.17.12",
|
||||
"lodash": "~4.17.10",
|
||||
"minimatch": "~3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
@ -1339,15 +1336,16 @@
|
|||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
|
||||
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
|
||||
"dev": true
|
||||
},
|
||||
"graceful-readlink": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
|
||||
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
|
||||
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
|
||||
"dev": true
|
||||
},
|
||||
"graphlib": {
|
||||
"version": "2.1.8",
|
||||
|
|
@ -1695,12 +1693,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
|
||||
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
|
||||
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.5.5",
|
||||
"ajv": "^6.12.3",
|
||||
"har-schema": "^2.0.0"
|
||||
}
|
||||
},
|
||||
|
|
@ -1763,6 +1761,17 @@
|
|||
"param-case": "2.1.x",
|
||||
"relateurl": "0.2.x",
|
||||
"uglify-js": "2.7.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
|
||||
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-readlink": ">= 1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"http-errors": {
|
||||
|
|
@ -1792,9 +1801,9 @@
|
|||
}
|
||||
},
|
||||
"http-parser-js": {
|
||||
"version": "0.4.10",
|
||||
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
|
||||
"integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=",
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz",
|
||||
"integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"http-signature": {
|
||||
|
|
@ -1970,9 +1979,9 @@
|
|||
"integrity": "sha1-DO7gsNLkkUOYGtEg1FjtVuqOGSQ="
|
||||
},
|
||||
"js-base64": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
|
||||
"integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==",
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
|
||||
"integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
|
|
@ -2093,9 +2102,9 @@
|
|||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
||||
},
|
||||
"longest": {
|
||||
"version": "1.0.1",
|
||||
|
|
@ -2204,18 +2213,18 @@
|
|||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.43.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
|
||||
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.26",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
|
||||
"integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mime-db": "1.43.0"
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
|
|
@ -2287,9 +2296,9 @@
|
|||
}
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
|
||||
"version": "2.14.1",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
|
||||
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
|
||||
"dev": true
|
||||
},
|
||||
"ncname": {
|
||||
|
|
@ -2695,9 +2704,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.9.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
|
||||
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==",
|
||||
"version": "6.9.4",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
|
||||
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"range-parser": {
|
||||
|
|
@ -2855,9 +2864,9 @@
|
|||
"integrity": "sha1-ExOHM2E/xEV7fhJH6Mt1HfeqVCk="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.0.tgz",
|
||||
"integrity": "sha512-LarL/PIKJvc09k1jaeT4kQb/8/7P+qV4qSnN2K80AES+OHdfZELAKVOBjxsvtToT/uLOfFbvYvKfZmV8cee7nA==",
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
|
||||
"integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.6"
|
||||
|
|
@ -2940,9 +2949,9 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"sass-graph": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
|
||||
"integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.6.tgz",
|
||||
"integrity": "sha512-MKuEYXFSGuRSi8FZ3A7imN1CeVn9Gpw0/SFJKdL1ejXJneI9a5rwlEZrKejhEFAA3O6yr3eIyl/WuvASvlT36g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.0.0",
|
||||
|
|
@ -2969,9 +2978,9 @@
|
|||
}
|
||||
},
|
||||
"yargs": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
|
||||
"integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz",
|
||||
"integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^3.0.0",
|
||||
|
|
@ -2986,7 +2995,7 @@
|
|||
"string-width": "^1.0.2",
|
||||
"which-module": "^1.0.0",
|
||||
"y18n": "^3.2.1",
|
||||
"yargs-parser": "^5.0.0"
|
||||
"yargs-parser": "5.0.0-security.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3133,9 +3142,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"spdx-correct": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
|
||||
"integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
|
||||
"integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"spdx-expression-parse": "^3.0.0",
|
||||
|
|
@ -3143,15 +3152,15 @@
|
|||
}
|
||||
},
|
||||
"spdx-exceptions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
|
||||
"integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
|
||||
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
|
||||
"dev": true
|
||||
},
|
||||
"spdx-expression-parse": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
|
||||
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
|
||||
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"spdx-exceptions": "^2.1.0",
|
||||
|
|
@ -3444,9 +3453,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
|
||||
"integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
|
|
@ -3498,20 +3507,20 @@
|
|||
}
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
|
||||
"integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==",
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||
"integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"http-parser-js": ">=0.4.0 <0.4.11",
|
||||
"http-parser-js": ">=0.5.1",
|
||||
"safe-buffer": ">=5.1.0",
|
||||
"websocket-extensions": ">=0.1.1"
|
||||
}
|
||||
},
|
||||
"websocket-extensions": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
|
||||
"integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
|
||||
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
||||
"dev": true
|
||||
},
|
||||
"which": {
|
||||
|
|
@ -3605,12 +3614,13 @@
|
|||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
|
||||
"integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
|
||||
"version": "5.0.0-security.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz",
|
||||
"integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^3.0.0"
|
||||
"camelcase": "^3.0.0",
|
||||
"object.assign": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"camelcase": {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
"backgrid-sizeable-columns": "0.1.1",
|
||||
"bootstrap": "3.3.7",
|
||||
"bootstrap-daterangepicker": "3.1.0",
|
||||
"d3": "3.5.17",
|
||||
"d3": "5.14.2",
|
||||
"d3-tip": "0.6.8",
|
||||
"dagre-d3": "0.6.4",
|
||||
"dropzone": "5.7.0",
|
||||
|
|
|
|||
|
|
@ -16,180 +16,12 @@
|
|||
|
||||
|
||||
/* graph.scss */
|
||||
|
||||
.node {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 10px;
|
||||
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 {
|
||||
fill: $color_suva_gray_approx;
|
||||
|
||||
&.highlight {
|
||||
cursor: pointer;
|
||||
fill: $color_havelock_blue_approx;
|
||||
text-decoration: underline;
|
||||
|
||||
tspan {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
circle {
|
||||
-moz-transition: all 0.3s;
|
||||
-webkit-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
stroke-width: 1.5px;
|
||||
|
||||
&.node-detail-highlight {
|
||||
stroke: $color_havelock_blue_approx;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
&.nodeImage {
|
||||
&.green:hover {
|
||||
stroke: #ffb203;
|
||||
}
|
||||
|
||||
&.blue:hover {
|
||||
stroke: #4b91e2;
|
||||
}
|
||||
|
||||
&.currentNode {
|
||||
stroke: #fb4200;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
-moz-transform: scale(1.4);
|
||||
-webkit-transform: scale(1.4);
|
||||
transform: scale(1.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
circle {
|
||||
-moz-transform: scale(1.4);
|
||||
-webkit-transform: scale(1.4);
|
||||
transform: scale(1.4);
|
||||
|
||||
&.nodeImage {
|
||||
&.green {
|
||||
stroke: #ffb203;
|
||||
}
|
||||
|
||||
&.blue {
|
||||
stroke: #4b91e2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invisible {
|
||||
.node circle {
|
||||
transition: all 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.edgePath {
|
||||
.path {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {}
|
||||
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: $color_celeste_approx;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.d3-tip {
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
padding: 12px;
|
||||
background: $black_80;
|
||||
color: $white;
|
||||
z-index: 999;
|
||||
max-width: 300px; //Instead of the line below you could use @include border-radius($radius, $vertical-radius)
|
||||
border-radius: 2px;
|
||||
|
||||
.tip-inner-scroll {
|
||||
overflow: auto;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
/* Creates a small triangle extender for the tooltip */
|
||||
&:after {
|
||||
box-sizing: border-box;
|
||||
display: inline;
|
||||
font-size: 10px;
|
||||
width: 100%;
|
||||
line-height: 1;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* Nrthward tooltips */
|
||||
&.n:after {
|
||||
content: "\25BC";
|
||||
margin: -1px 0 0 0;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Eastward tooltips */
|
||||
&.e:after {
|
||||
content: "\25C0";
|
||||
margin: -4px 0 0 0;
|
||||
top: 50%;
|
||||
left: -8px;
|
||||
}
|
||||
|
||||
/* Southward tooltips */
|
||||
&.s:after {
|
||||
content: "\25B2";
|
||||
margin: 0 0 1px 0;
|
||||
top: -8px;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Westward tooltips */
|
||||
&.w:after {
|
||||
content: "\25B6";
|
||||
margin: -4px 0 0 -1px;
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
g.type-TK>rect {
|
||||
fill: $color_bright_turquoise_approx;
|
||||
}
|
||||
|
||||
|
||||
.graph-toolbar {
|
||||
background-color: $white;
|
||||
margin-bottom: 10px;
|
||||
|
|
@ -199,7 +31,7 @@ g.type-TK>rect {
|
|||
.legends {
|
||||
>i {
|
||||
>span {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-family: "Source Sans Pro";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -357,7 +189,7 @@ span#zoom_in {
|
|||
}
|
||||
|
||||
.active.fullscreen-mode {
|
||||
position: fixed;
|
||||
position: fixed !important;
|
||||
height: 100% !important;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
|
@ -367,6 +199,11 @@ span#zoom_in {
|
|||
padding: 0 !important;
|
||||
z-index: 9999;
|
||||
overflow: hidden !important;
|
||||
background: white;
|
||||
|
||||
.systemTypeTree {
|
||||
height: 100vh !important;
|
||||
}
|
||||
|
||||
.resizeGraph {
|
||||
position: fixed;
|
||||
|
|
@ -386,40 +223,6 @@ span#zoom_in {
|
|||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
|
@ -461,4 +264,17 @@ span#zoom_in {
|
|||
to {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.mini-map-type-system {
|
||||
background: white;
|
||||
width: 200px;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
|
||||
&>svg {
|
||||
box-shadow: 0px 0px 3px 1px #80808080;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -68,6 +68,7 @@
|
|||
<link href="js/libs/dropzone/css/dropzone.css?bust=<%- bust %>" rel="stylesheet">
|
||||
<link href="js/libs/jstree/css/default/default-theme.min.css?bust=<%- bust %>" rel="stylesheet" />
|
||||
<link href="js/libs/pretty-checkbox/css/pretty-checkbox.min.css?bust=<%- bust %>" rel="stylesheet" />
|
||||
<link href="js/external_lib/atlas-lineage/dist/styles.css?bust=<%- bust %>" rel="stylesheet">
|
||||
<link href="css/style.css?bust=<%- bust %>" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,204 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed 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.
|
||||
|
||||
|
||||
=======================================================================
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,2 @@
|
|||
.node{cursor:pointer}.node text{font-size:10px;font-family:sans-serif}.node rect{stroke:#999;fill:#fff;stroke-width:1.5px}.node rect.serach-rect{stroke:#37bb9b;fill:transparent;stroke-width:2.5px}.node .label{fill:#868686}.node .label.highlight{cursor:pointer;fill:#4a90e2;text-decoration:underline}.node .label.highlight tspan{font-weight:400}.node circle{-moz-transition:all 0.3s;-webkit-transition:all 0.3s;transition:all 0.3s;stroke-width:1.5px}.node circle.node-detail-highlight{stroke:#4a90e2;stroke-width:2px}.node circle.nodeImage.green:hover{stroke:#ffb203}.node circle.nodeImage.blue:hover{stroke:#4b91e2}.node circle.nodeImage.currentNode{stroke:#fb4200}.node circle.nodeImage:hover{-moz-transform:scale(1.4);-webkit-transform:scale(1.4);transform:scale(1.4)}.node.active circle{-moz-transform:scale(1.4);-webkit-transform:scale(1.4);transform:scale(1.4)}.node.active circle.nodeImage.green{stroke:#ffb203}.node.active circle.nodeImage.blue{stroke:#4b91e2}.legends>span{margin-right:8px;font-family:Source Sans Pro}svg.hover g.node{opacity:0.1 !important}svg.hover g.edgePath{opacity:0 !important}svg.hover g.node.hover-active-node,svg.hover g.edgePath.hover-active-path{opacity:1 !important}.invisible .node circle{transition:all 0s}.edgePath .path{cursor:pointer}.link{fill:none;stroke:#ccc;stroke-width:1.5px}.text-center{text-align:center}.d3-tip{line-height:1;font-weight:bold;padding:12px;background:rgba(0,0,0,0.8);color:#fff;z-index:999;max-width:300px;border-radius:2px}.d3-tip .tip-inner-scroll{overflow:auto;max-height:300px}.d3-tip .tip-inner-scroll h5{margin:7px 0px}.d3-tip:after{box-sizing:border-box;display:inline;font-size:10px;width:100%;line-height:1;color:rgba(0,0,0,0.8);position:absolute}.d3-tip.n:after{content:"\25BC";margin:-1px 0 0 0;top:100%;left:0;text-align:center}.d3-tip.e:after{content:"\25C0";margin:-4px 0 0 0;top:50%;left:-8px}.d3-tip.s:after{content:"\25B2";margin:0 0 1px 0;top:-8px;left:0;text-align:center}.d3-tip.w:after{content:"\25B6";margin:-4px 0 0 -1px;top:50%;left:100%}g.type-TK>rect{fill:#00ffd0}.fullscreen-mode{position:fixed;height:100% !important;top:0;bottom:0;left:0;width:100%;right:0;padding:0 !important;z-index:9999;overflow:hidden !important}.fullscreen-mode .resizeGraph{position:fixed;height:100% !important}.fullscreen-mode .resizeGraph .ui-resizable-handle{display:none}.fullscreen-mode .lineage-box{padding:10px !important}.fullscreen-mode .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}.hidden-svg{visibility:hidden}@-webkit-keyframes blink{from{opacity:0.2}to{opacity:0.5}}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "atlas-lineage-module",
|
||||
"version": "1.0.0",
|
||||
"description": "The module will help to render the lineage graph with the help dagre-d3,d3 js lib",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"start": "NODE_ENV=development webpack --watch",
|
||||
"build": "webpack"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/apache/atlas.git"
|
||||
},
|
||||
"keywords": [
|
||||
"lineage",
|
||||
"dagre-d3",
|
||||
"d3"
|
||||
],
|
||||
"author": "kevalbhatt",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/apache/atlas/issues"
|
||||
},
|
||||
"homepage": "https://github.com/apache/atlas#readme",
|
||||
"dependencies": {
|
||||
"d3-tip": "^0.9.1",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"platform": "^1.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.6",
|
||||
"@babel/preset-env": "^7.9.6",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"css-loader": "^3.5.3",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"path": "^0.12.7",
|
||||
"sass": "^1.26.5",
|
||||
"sass-loader": "^8.0.2",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export default {
|
||||
entityStateReadOnly: {
|
||||
ACTIVE: false,
|
||||
DELETED: true,
|
||||
STATUS_ACTIVE: false,
|
||||
STATUS_DELETED: true
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,361 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
import Enums from "../Enums";
|
||||
import { curveBasis } from "d3-shape";
|
||||
|
||||
const DataUtils = {
|
||||
/**
|
||||
* [getBaseUrl description]
|
||||
* @param {[type]} url [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getBaseUrl: function(url) {
|
||||
return url.replace(/\/[\w-]+.(jsp|html)|\/+$/gi, "");
|
||||
},
|
||||
/**
|
||||
* [getEntityIconPath description]
|
||||
* @param {[type]} options.entityData [description]
|
||||
* @param {Object} options.errorUrl } [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getEntityIconPath: function({ entityData, errorUrl } = {}) {
|
||||
var serviceType,
|
||||
status,
|
||||
typeName,
|
||||
iconBasePath = this.getBaseUrl(window.location.pathname) + Globals.entityImgPath;
|
||||
if (entityData) {
|
||||
typeName = entityData.typeName;
|
||||
serviceType = entityData && entityData.serviceType;
|
||||
status = entityData && entityData.status;
|
||||
}
|
||||
|
||||
function getImgPath(imageName) {
|
||||
return iconBasePath + (Enums.entityStateReadOnly[status] ? "disabled/" + imageName : imageName);
|
||||
}
|
||||
|
||||
function getDefaultImgPath() {
|
||||
if (entityData.isProcess) {
|
||||
if (Enums.entityStateReadOnly[status]) {
|
||||
return iconBasePath + "disabled/process.png";
|
||||
} else {
|
||||
return iconBasePath + "process.png";
|
||||
}
|
||||
} else {
|
||||
if (Enums.entityStateReadOnly[status]) {
|
||||
return iconBasePath + "disabled/table.png";
|
||||
} else {
|
||||
return iconBasePath + "table.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entityData) {
|
||||
if (errorUrl) {
|
||||
var isErrorInTypeName = errorUrl && errorUrl.match("entity-icon/" + typeName + ".png|disabled/" + typeName + ".png") ? true : false;
|
||||
if (serviceType && isErrorInTypeName) {
|
||||
var imageName = serviceType + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else {
|
||||
return getDefaultImgPath();
|
||||
}
|
||||
} else if (entityData.typeName) {
|
||||
var imageName = entityData.typeName + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else {
|
||||
return getDefaultImgPath();
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* [isProcess description]
|
||||
* @param {[type]} options.typeName [description]
|
||||
* @param {[type]} options.superTypes [description]
|
||||
* @param {[type]} options.entityDef [description]
|
||||
* @return {Boolean} [description]
|
||||
*/
|
||||
isProcess: function({ typeName, superTypes, entityDef }) {
|
||||
if (typeName == "Process") {
|
||||
return true;
|
||||
}
|
||||
return superTypes.indexOf("Process") > -1;
|
||||
},
|
||||
/**
|
||||
* [isDeleted description]
|
||||
* @param {[type]} node [description]
|
||||
* @return {Boolean} [description]
|
||||
*/
|
||||
isDeleted: function(node) {
|
||||
if (node === undefined) {
|
||||
return;
|
||||
}
|
||||
return Enums.entityStateReadOnly[node.status];
|
||||
},
|
||||
isNodeToBeUpdated: function(node, filterObj) {
|
||||
var isProcessHideCheck = filterObj.isProcessHideCheck,
|
||||
isDeletedEntityHideCheck = filterObj.isDeletedEntityHideCheck;
|
||||
var returnObj = {
|
||||
isProcess: isProcessHideCheck && node.isProcess,
|
||||
isDeleted: isDeletedEntityHideCheck && node.isDeleted
|
||||
};
|
||||
returnObj["update"] = returnObj.isProcess || returnObj.isDeleted;
|
||||
return returnObj;
|
||||
},
|
||||
/**
|
||||
* [getServiceType description]
|
||||
* @param {[type]} options.typeName [description]
|
||||
* @param {[type]} options.entityDef [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getServiceType: function({ typeName, entityDef }) {
|
||||
var serviceType = null;
|
||||
if (typeName) {
|
||||
if (entityDef) {
|
||||
serviceType = entityDef.serviceType || null;
|
||||
}
|
||||
}
|
||||
return serviceType;
|
||||
},
|
||||
/**
|
||||
* [getEntityDef description]
|
||||
* @param {[type]} options.typeName [description]
|
||||
* @param {[type]} options.entityDefCollection [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getEntityDef: function({ typeName, entityDefCollection }) {
|
||||
var entityDef = null;
|
||||
if (typeName) {
|
||||
entityDef = entityDefCollection.find(function(obj) {
|
||||
return obj.name == typeName;
|
||||
});
|
||||
}
|
||||
return entityDef;
|
||||
},
|
||||
/**
|
||||
* [getNestedSuperTypes description]
|
||||
* @param {[type]} options.entityDef [description]
|
||||
* @param {[type]} options.entityDefCollection [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getNestedSuperTypes: function({ entityDef, entityDefCollection }) {
|
||||
var data = entityDef,
|
||||
collection = entityDefCollection,
|
||||
superTypes = new Set();
|
||||
|
||||
var getData = function(data, collection) {
|
||||
if (data) {
|
||||
if (data.superTypes && data.superTypes.length) {
|
||||
data.superTypes.forEach(function(superTypeName) {
|
||||
superTypes.add(superTypeName);
|
||||
var collectionData = collection.find(function(obj) {
|
||||
obj.name === superTypeName;
|
||||
});
|
||||
if (collectionData) {
|
||||
getData(collectionData, collection);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
getData(data, collection);
|
||||
return Array.from(superTypes);
|
||||
},
|
||||
generateData: function({ data = {}, filterObj, entityDefCollection, g, guid, setGraphEdge, setGraphNode }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
var relations = data.relations || {},
|
||||
guidEntityMap = data.guidEntityMap || {},
|
||||
isHideFilterOn = filterObj.isProcessHideCheck || filterObj.isDeletedEntityHideCheck,
|
||||
newHashMap = {},
|
||||
styleObj = {
|
||||
fill: "none",
|
||||
stroke: "#ffb203",
|
||||
width: 3
|
||||
},
|
||||
makeNodeData = (relationObj) => {
|
||||
if (relationObj) {
|
||||
if (relationObj.updatedValues) {
|
||||
return relationObj;
|
||||
}
|
||||
var obj = Object.assign(relationObj, {
|
||||
shape: "img",
|
||||
updatedValues: true,
|
||||
label: relationObj.displayText.trunc(18),
|
||||
toolTipLabel: relationObj.displayText,
|
||||
id: relationObj.guid,
|
||||
isLineage: true,
|
||||
isIncomplete: relationObj.isIncomplete,
|
||||
entityDef: this.getEntityDef({ typeName: relationObj.typeName, entityDefCollection })
|
||||
});
|
||||
obj["serviceType"] = this.getServiceType(obj);
|
||||
obj["superTypes"] = this.getNestedSuperTypes({
|
||||
...obj,
|
||||
entityDefCollection: entityDefCollection
|
||||
});
|
||||
obj["isProcess"] = this.isProcess(obj);
|
||||
obj["isDeleted"] = this.isDeleted(obj);
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
crateLineageRelationshipHashMap = function({ relations } = {}) {
|
||||
var newHashMap = {};
|
||||
relations.forEach(function(obj) {
|
||||
if (newHashMap[obj.fromEntityId]) {
|
||||
newHashMap[obj.fromEntityId].push(obj.toEntityId);
|
||||
} else {
|
||||
newHashMap[obj.fromEntityId] = [obj.toEntityId];
|
||||
}
|
||||
});
|
||||
return newHashMap;
|
||||
},
|
||||
getStyleObjStr = function(styleObj) {
|
||||
return "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width;
|
||||
},
|
||||
getNewToNodeRelationship = (toNodeGuid, filterObj) => {
|
||||
if (toNodeGuid && relationshipMap[toNodeGuid]) {
|
||||
var newRelationship = [];
|
||||
relationshipMap[toNodeGuid].forEach((guid) => {
|
||||
var nodeToBeUpdated = this.isNodeToBeUpdated(makeNodeData(guidEntityMap[guid]), filterObj);
|
||||
if (nodeToBeUpdated.update) {
|
||||
var newRelation = getNewToNodeRelationship(guid, filterObj);
|
||||
if (newRelation) {
|
||||
newRelationship = newRelationship.concat(newRelation);
|
||||
}
|
||||
} else {
|
||||
newRelationship.push(guid);
|
||||
}
|
||||
});
|
||||
return newRelationship;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
getToNodeRelation = (toNodes, fromNodeToBeUpdated, filterObj) => {
|
||||
var toNodeRelationship = [];
|
||||
toNodes.forEach((toNodeGuid) => {
|
||||
var toNodeToBeUpdated = this.isNodeToBeUpdated(makeNodeData(guidEntityMap[toNodeGuid]), filterObj);
|
||||
if (toNodeToBeUpdated.update) {
|
||||
// To node need to updated
|
||||
if (pendingFromRelationship[toNodeGuid]) {
|
||||
toNodeRelationship = toNodeRelationship.concat(pendingFromRelationship[toNodeGuid]);
|
||||
} else {
|
||||
var newToNodeRelationship = getNewToNodeRelationship(toNodeGuid, filterObj);
|
||||
if (newToNodeRelationship) {
|
||||
toNodeRelationship = toNodeRelationship.concat(newToNodeRelationship);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//when bothe node not to be updated.
|
||||
toNodeRelationship.push(toNodeGuid);
|
||||
}
|
||||
});
|
||||
return toNodeRelationship;
|
||||
},
|
||||
setNode = (guid) => {
|
||||
if (!g._nodes[guid]) {
|
||||
var nodeData = makeNodeData(guidEntityMap[guid]);
|
||||
setGraphNode(guid, nodeData);
|
||||
return nodeData;
|
||||
} else {
|
||||
return g._nodes[guid];
|
||||
}
|
||||
},
|
||||
setEdge = function(fromNodeGuid, toNodeGuid, opt = {}) {
|
||||
setGraphEdge(fromNodeGuid, toNodeGuid, {
|
||||
arrowhead: "arrowPoint",
|
||||
curve: curveBasis,
|
||||
style: getStyleObjStr(styleObj),
|
||||
styleObj: styleObj,
|
||||
...opt
|
||||
});
|
||||
},
|
||||
setGraphData = function(fromEntityId, toEntityId) {
|
||||
setNode(fromEntityId);
|
||||
setNode(toEntityId);
|
||||
setEdge(fromEntityId, toEntityId);
|
||||
},
|
||||
pendingFromRelationship = {};
|
||||
if (isHideFilterOn) {
|
||||
var relationshipMap = crateLineageRelationshipHashMap(data);
|
||||
Object.keys(relationshipMap).forEach((fromNodeGuid) => {
|
||||
var toNodes = relationshipMap[fromNodeGuid],
|
||||
fromNodeToBeUpdated = this.isNodeToBeUpdated(makeNodeData(guidEntityMap[fromNodeGuid]), filterObj),
|
||||
toNodeList = getToNodeRelation(toNodes, fromNodeToBeUpdated, filterObj);
|
||||
if (fromNodeToBeUpdated.update) {
|
||||
if (pendingFromRelationship[fromNodeGuid]) {
|
||||
pendingFromRelationship[fromNodeGuid] = pendingFromRelationship[fromNodeGuid].concat(toNodeList);
|
||||
} else {
|
||||
pendingFromRelationship[fromNodeGuid] = toNodeList;
|
||||
}
|
||||
} else {
|
||||
toNodeList.forEach(function(toNodeGuid) {
|
||||
setGraphData(fromNodeGuid, toNodeGuid);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
relations.forEach(function(obj) {
|
||||
setGraphData(obj.fromEntityId, obj.toEntityId);
|
||||
});
|
||||
}
|
||||
if (g._nodes[guid]) {
|
||||
if (g._nodes[guid]) {
|
||||
g._nodes[guid]["isLineage"] = false;
|
||||
}
|
||||
this.findImpactNodeAndUpdateData({
|
||||
guid,
|
||||
g,
|
||||
setEdge,
|
||||
getStyleObjStr
|
||||
});
|
||||
}
|
||||
resolve(g);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
},
|
||||
findImpactNodeAndUpdateData: function({ guid, getStyleObjStr, g, setEdge }) {
|
||||
var that = this,
|
||||
traversedMap = {},
|
||||
styleObj = {
|
||||
fill: "none",
|
||||
stroke: "#fb4200",
|
||||
width: 3
|
||||
},
|
||||
traversed = function(toNodeList = {}, fromNodeGuid) {
|
||||
let toNodeKeyList = Object.keys(toNodeList);
|
||||
if (toNodeKeyList.length) {
|
||||
if (!traversedMap[fromNodeGuid]) {
|
||||
traversedMap[fromNodeGuid] = true;
|
||||
toNodeKeyList.forEach(function(toNodeGuid) {
|
||||
if (g._nodes[toNodeGuid]) {
|
||||
g._nodes[toNodeGuid]["isLineage"] = false;
|
||||
}
|
||||
setEdge(fromNodeGuid, toNodeGuid, {
|
||||
style: getStyleObjStr(styleObj),
|
||||
styleObj: styleObj
|
||||
});
|
||||
traversed(g._sucs[toNodeGuid], toNodeGuid);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
traversed(g._sucs[guid], guid);
|
||||
}
|
||||
};
|
||||
export default DataUtils;
|
||||
|
|
@ -0,0 +1,608 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { select, event } from "d3-selection";
|
||||
import { zoom, zoomIdentity } from "d3-zoom";
|
||||
import { drag } from "d3-drag";
|
||||
import { line, curveBasis } from "d3-shape";
|
||||
|
||||
import platform from "platform";
|
||||
|
||||
import Enums from "../Enums";
|
||||
|
||||
const LineageUtils = {
|
||||
/**
|
||||
* [nodeArrowDistance variable use to define the distance between arrow and node]
|
||||
* @type {Number}
|
||||
*/
|
||||
nodeArrowDistance: 24,
|
||||
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);
|
||||
});
|
||||
},
|
||||
refreshGraphForIE: function ({ edgePathEl }) {
|
||||
var 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);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* [dragNode description]
|
||||
* @param {[type]} options.g [description]
|
||||
* @param {[type]} options.svg [description]
|
||||
* @param {[type]} options.guid [description]
|
||||
* @param {[type]} options.edgePathEl [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
dragNode: function ({ g, svg, guid, edgePathEl }) {
|
||||
var dragHelper = {
|
||||
dragmove: function (el, d) {
|
||||
var node = select(el),
|
||||
selectedNode = g.node(d),
|
||||
prevX = selectedNode.x,
|
||||
prevY = selectedNode.y;
|
||||
|
||||
selectedNode.x += event.dx;
|
||||
selectedNode.y += event.dy;
|
||||
node.attr("transform", "translate(" + selectedNode.x + "," + selectedNode.y + ")");
|
||||
|
||||
var dx = selectedNode.x - prevX,
|
||||
dy = selectedNode.y - prevY;
|
||||
|
||||
g.edges().forEach((e) => {
|
||||
if (e.v == d || e.w == d) {
|
||||
var edge = g.edge(e.v, e.w);
|
||||
this.translateEdge(edge, dx, dy);
|
||||
select(edge.elem).select("path").attr("d", this.calcPoints(e));
|
||||
}
|
||||
});
|
||||
//LineageUtils.refreshGraphForIE({ edgePathEl: 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 line()
|
||||
.x(function (d) {
|
||||
return d.x;
|
||||
})
|
||||
.y(function (d) {
|
||||
return d.y;
|
||||
})
|
||||
.curve(curveBasis)(points);
|
||||
},
|
||||
intersectRect: (node, point) => {
|
||||
var x = node.x,
|
||||
y = node.y,
|
||||
dx = point.x - x,
|
||||
dy = point.y - y,
|
||||
nodeDistance = guid ? this.nodeArrowDistance + 3 : this.nodeArrowDistance,
|
||||
w = nodeDistance,
|
||||
h = nodeDistance,
|
||||
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
|
||||
};
|
||||
}
|
||||
};
|
||||
var dragNodeHandler = drag().on("drag", function (d) {
|
||||
dragHelper.dragmove.call(dragHelper, this, d);
|
||||
}),
|
||||
dragEdgePathHandler = drag().on("drag", function (d) {
|
||||
dragHelper.translateEdge(g.edge(d.v, d.w), event.dx, event.dy);
|
||||
var edgeObj = g.edge(d.v, d.w);
|
||||
select(edgeObj.elem).select("path").attr("d", dragHelper.calcPoints(d));
|
||||
});
|
||||
|
||||
dragNodeHandler(svg.selectAll("g.node"));
|
||||
dragEdgePathHandler(svg.selectAll("g.edgePath"));
|
||||
},
|
||||
zoomIn: function ({ svg, scaleFactor = 1.3 }) {
|
||||
this.d3Zoom.scaleBy(svg.transition().duration(750), scaleFactor);
|
||||
},
|
||||
zoomOut: function ({ svg, scaleFactor = 0.8 }) {
|
||||
this.d3Zoom.scaleBy(svg.transition().duration(750), scaleFactor);
|
||||
},
|
||||
zoom: function ({ svg, xa, ya, scale }) {
|
||||
svg.transition().duration(750).call(this.d3Zoom.transform, zoomIdentity.translate(xa, ya).scale(scale));
|
||||
},
|
||||
fitToScreen: function ({ svg }) {
|
||||
var node = svg.node();
|
||||
var bounds = node.getBBox();
|
||||
|
||||
var parent = node.parentElement,
|
||||
fullWidth = parent.clientWidth,
|
||||
fullHeight = parent.clientHeight;
|
||||
|
||||
var width = bounds.width,
|
||||
height = bounds.height;
|
||||
var midX = bounds.x + width / 2,
|
||||
midY = bounds.y + height / 2;
|
||||
|
||||
var scale = (scale || 0.95) / Math.max(width / fullWidth, height / fullHeight),
|
||||
xa = fullWidth / 2 - scale * midX,
|
||||
ya = fullHeight / 2 - scale * midY;
|
||||
this.zoom({ svg, xa, ya, scale });
|
||||
},
|
||||
/**
|
||||
* [centerNode description]
|
||||
* @param {[type]} options.guid [description]
|
||||
* @param {[type]} options.g [description]
|
||||
* @param {[type]} options.svg [description]
|
||||
* @param {[type]} options.svgGroupEl [description]
|
||||
* @param {[type]} options.edgePathEl [description]
|
||||
* @param {[type]} options.width [description]
|
||||
* @param {[type]} options.height [description]
|
||||
* @param {[type]} options.onCenterZoomed [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
centerNode: function ({ guid, g, svg, svgGroupEl, edgePathEl, width, height, fitToScreen, onCenterZoomed }) {
|
||||
this.d3Zoom = zoom();
|
||||
svg.call(this.d3Zoom).on("dblclick.zoom", null);
|
||||
|
||||
// restrict events
|
||||
|
||||
let selectedNodeEl = svg.selectAll("g.nodes>g[id='" + guid + "']"),
|
||||
zoomListener = this.d3Zoom.scaleExtent([0.01, 50]).on("zoom", function () {
|
||||
svgGroupEl.attr("transform", event.transform);
|
||||
}),
|
||||
x = null,
|
||||
y = null,
|
||||
scale = 1.2;
|
||||
if (selectedNodeEl.empty()) {
|
||||
if (fitToScreen) {
|
||||
this.fitToScreen({ svg });
|
||||
return;
|
||||
} else {
|
||||
x = g.graph().width / 2;
|
||||
y = g.graph().height / 2;
|
||||
}
|
||||
} else {
|
||||
var matrix = selectedNodeEl
|
||||
.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(" ");
|
||||
// }
|
||||
x = matrix[0];
|
||||
y = matrix[1];
|
||||
}
|
||||
|
||||
var xa = -(x * scale - width / 2),
|
||||
ya = -(y * scale - height / 2);
|
||||
this.zoom({ svg, xa, ya, scale });
|
||||
svg.transition().duration(750).call(this.d3Zoom.transform, zoomIdentity.translate(xa, ya).scale(scale));
|
||||
|
||||
if (onCenterZoomed) {
|
||||
onCenterZoomed({ newScale: scale, newTranslate: [xa, ya], d3Zoom: this.d3Zoom, selectedNodeEl });
|
||||
}
|
||||
// if (platform.name === "IE") {
|
||||
// LineageUtils.refreshGraphForIE({ edgePathEl: edgePathEl });
|
||||
// }
|
||||
},
|
||||
/**
|
||||
* [getToolTipDirection description]
|
||||
* @param {[type]} options.el [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getToolTipDirection: function ({ el }) {
|
||||
var width = select("body").node().getBoundingClientRect().width,
|
||||
currentELWidth = select(el).node().getBoundingClientRect(),
|
||||
direction = "e";
|
||||
if (width - currentELWidth.left < 330) {
|
||||
direction = width - currentELWidth.left < 330 && currentELWidth.top < 400 ? "sw" : "w";
|
||||
if (width - currentELWidth.left < 330 && currentELWidth.top > 600) {
|
||||
direction = "nw";
|
||||
}
|
||||
} else if (currentELWidth.top > 600) {
|
||||
direction = width - currentELWidth.left < 330 && currentELWidth.top > 600 ? "nw" : "n";
|
||||
if (currentELWidth.left < 50) {
|
||||
direction = "ne";
|
||||
}
|
||||
} else if (currentELWidth.top < 400) {
|
||||
direction = currentELWidth.left < 50 ? "se" : "s";
|
||||
}
|
||||
return direction;
|
||||
},
|
||||
/**
|
||||
* [onHoverFade description]
|
||||
* @param {[type]} options.svg [description]
|
||||
* @param {[type]} options.g [description]
|
||||
* @param {[type]} options.mouseenter [description]
|
||||
* @param {[type]} options.opacity [description]
|
||||
* @param {[type]} options.nodesToHighlight [description]
|
||||
* @param {[type]} options.hoveredNode [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
onHoverFade: function ({ svg, g, mouseenter, nodesToHighlight, hoveredNode }) {
|
||||
var node = svg.selectAll(".node"),
|
||||
path = svg.selectAll(".edgePath"),
|
||||
isConnected = function (a, b, o) {
|
||||
if (a === o || (b && b.length && b.indexOf(o) != -1)) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if (mouseenter) {
|
||||
svg.classed("hover", true);
|
||||
var nextNode = g.successors(hoveredNode),
|
||||
previousNode = g.predecessors(hoveredNode),
|
||||
nodesToHighlight = nextNode.concat(previousNode);
|
||||
node.classed("hover-active-node", function (currentNode, i, nodes) {
|
||||
if (isConnected(hoveredNode, nodesToHighlight, currentNode)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
path.classed("hover-active-path", function (c) {
|
||||
var _thisOpacity = c.v === hoveredNode || c.w === hoveredNode ? 1 : 0;
|
||||
if (_thisOpacity) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
svg.classed("hover", false);
|
||||
node.classed("hover-active-node", false);
|
||||
path.classed("hover-active-path", false);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* [getBaseUrl description]
|
||||
* @param {[type]} path [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getBaseUrl: function (url = window.location.pathname) {
|
||||
return url.replace(/\/[\w-]+.(jsp|html)|\/+$/gi, "");
|
||||
},
|
||||
getEntityIconPath: function ({ entityData, errorUrl, imgBasePath }) {
|
||||
var iconBasePath = this.getBaseUrl() + (imgBasePath || "/img/entity-icon/");
|
||||
if (entityData) {
|
||||
let { typeName, serviceType, status, isProcess } = entityData;
|
||||
|
||||
function getImgPath(imageName) {
|
||||
return iconBasePath + (Enums.entityStateReadOnly[status] ? "disabled/" + imageName : imageName);
|
||||
}
|
||||
|
||||
function getDefaultImgPath() {
|
||||
if (isProcess) {
|
||||
if (Enums.entityStateReadOnly[status]) {
|
||||
return iconBasePath + "disabled/process.png";
|
||||
} else {
|
||||
return iconBasePath + "process.png";
|
||||
}
|
||||
} else {
|
||||
if (Enums.entityStateReadOnly[status]) {
|
||||
return iconBasePath + "disabled/table.png";
|
||||
} else {
|
||||
return iconBasePath + "table.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errorUrl) {
|
||||
// Check if the default img path has error, if yes then stop recursion.
|
||||
if (errorUrl.indexOf("table.png") > -1 || errorUrl.indexOf("process.png") > -1) {
|
||||
return null;
|
||||
}
|
||||
var isErrorInTypeName = errorUrl && errorUrl.match("entity-icon/" + typeName + ".png|disabled/" + typeName + ".png") ? true : false;
|
||||
if (serviceType && isErrorInTypeName) {
|
||||
var imageName = serviceType + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else {
|
||||
return getDefaultImgPath();
|
||||
}
|
||||
} else if (typeName) {
|
||||
var imageName = typeName + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else if (serviceType) {
|
||||
var imageName = serviceType + ".png";
|
||||
return getImgPath(imageName);
|
||||
} else {
|
||||
return getDefaultImgPath();
|
||||
}
|
||||
}
|
||||
},
|
||||
base64Encode: function (file, callback) {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", () => callback(reader.result));
|
||||
reader.readAsDataURL(file);
|
||||
},
|
||||
imgShapeRender: function (parent, bbox, node, { dagreD3, defsEl, imgBasePath, guid }) {
|
||||
var that = this,
|
||||
viewGuid = guid,
|
||||
imageIconPath = this.getEntityIconPath({ entityData: node, imgBasePath }),
|
||||
imgName = imageIconPath.split("/").pop();
|
||||
if (this.imageObject === undefined) {
|
||||
this.imageObject = {};
|
||||
}
|
||||
if (node.isDeleted) {
|
||||
imgName = "deleted_" + imgName;
|
||||
}
|
||||
if (node.id == viewGuid) {
|
||||
var currentNode = true;
|
||||
}
|
||||
var shapeSvg = parent
|
||||
.append("circle")
|
||||
.attr("fill", "url(#img_" + imgName + ")")
|
||||
.attr("r", "24px")
|
||||
.attr("data-stroke", node.id)
|
||||
.attr("stroke-width", "2px")
|
||||
.attr("class", "nodeImage " + (currentNode ? "currentNode" : node.isProcess ? "process" : "node"));
|
||||
if (currentNode) {
|
||||
shapeSvg.attr("stroke", "#fb4200");
|
||||
}
|
||||
if (node.isIncomplete === true) {
|
||||
parent.attr("class", "node isIncomplete show");
|
||||
parent
|
||||
.insert("foreignObject")
|
||||
.attr("x", "-25")
|
||||
.attr("y", "-25")
|
||||
.attr("width", "50")
|
||||
.attr("height", "50")
|
||||
.append("xhtml:div")
|
||||
.insert("i")
|
||||
.attr("class", "fa fa-hourglass-half");
|
||||
}
|
||||
|
||||
if (defsEl.select('pattern[id="img_' + imgName + '"]').empty()) {
|
||||
defsEl
|
||||
.append("pattern")
|
||||
.attr("x", "0%")
|
||||
.attr("y", "0%")
|
||||
.attr("patternUnits", "objectBoundingBox")
|
||||
.attr("id", "img_" + imgName)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.append("image")
|
||||
.attr("href", function (d) {
|
||||
var imgEl = this;
|
||||
if (node) {
|
||||
var getImageData = function (options) {
|
||||
var imagePath = options.imagePath,
|
||||
ajaxOptions = {
|
||||
url: imagePath,
|
||||
method: "GET",
|
||||
cache: true
|
||||
};
|
||||
|
||||
// if (platform.name !== "IE") {
|
||||
// ajaxOptions["mimeType"] = "text/plain; charset=x-user-defined";
|
||||
// }
|
||||
shapeSvg.attr("data-iconpath", imagePath);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
if (platform.name !== "IE") {
|
||||
that.base64Encode(this.response, (url) => {
|
||||
that.imageObject[imageIconPath] = url;
|
||||
select(imgEl).attr("xlink:href", url);
|
||||
});
|
||||
} else {
|
||||
that.imageObject[imageIconPath] = imagePath;
|
||||
}
|
||||
if (imageIconPath !== shapeSvg.attr("data-iconpath")) {
|
||||
shapeSvg.attr("data-iconpathorigin", imageIconPath);
|
||||
}
|
||||
} else if (xhr.status === 404) {
|
||||
const imgPath = that.getEntityIconPath({ entityData: node, errorUrl: imagePath });
|
||||
if (imgPath === null) {
|
||||
const patternEL = select(imgEl.parentElement);
|
||||
patternEL.select("image").remove();
|
||||
patternEL
|
||||
.attr("patternContentUnits", "objectBoundingBox")
|
||||
.append("circle")
|
||||
.attr("r", "24px")
|
||||
.attr("fill", "#e8e8e8");
|
||||
} else {
|
||||
getImageData({
|
||||
imagePath: imgPath
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.responseType = "blob";
|
||||
xhr.open(ajaxOptions.method, ajaxOptions.url, true);
|
||||
xhr.send(null);
|
||||
};
|
||||
getImageData({
|
||||
imagePath: imageIconPath
|
||||
});
|
||||
}
|
||||
})
|
||||
.attr("x", "4")
|
||||
.attr("y", currentNode ? "3" : "4")
|
||||
.attr("width", "40")
|
||||
.attr("height", "40");
|
||||
}
|
||||
|
||||
node.intersect = function (point) {
|
||||
return dagreD3.intersect.circle(node, currentNode ? that.nodeArrowDistance + 3 : that.nodeArrowDistance, point);
|
||||
};
|
||||
return shapeSvg;
|
||||
},
|
||||
/**
|
||||
* [arrowPointRender description]
|
||||
* @param {[type]} {parent, id, edge, type, viewOptions [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
arrowPointRender: function (parent, id, edge, type, { dagreD3 }) {
|
||||
var node = parent.node(),
|
||||
parentNode = node ? node.parentNode : parent;
|
||||
select(parentNode)
|
||||
.select("path.path")
|
||||
.attr("marker-end", "url(#" + id + ")");
|
||||
var marker = parent
|
||||
.append("marker")
|
||||
.attr("id", id)
|
||||
.attr("viewBox", "0 0 10 10")
|
||||
.attr("refX", 8)
|
||||
.attr("refY", 5)
|
||||
.attr("markerUnits", "strokeWidth")
|
||||
.attr("markerWidth", 4)
|
||||
.attr("markerHeight", 4)
|
||||
.attr("orient", "auto");
|
||||
|
||||
var path = marker.append("path").attr("d", "M 0 0 L 10 5 L 0 10 z").style("fill", edge.styleObj.stroke);
|
||||
dagreD3.util.applyStyle(path, edge[type + "Style"]);
|
||||
},
|
||||
/**
|
||||
* [saveSvg description]
|
||||
* @param {[type]} options.svg [description]
|
||||
* @param {[type]} options.width [description]
|
||||
* @param {[type]} options.height [description]
|
||||
* @param {[type]} options.downloadFileName [description]
|
||||
* @param {[type]} options.onExportLineage [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
saveSvg: function ({ svg, width, height, downloadFileName, onExportLineage }) {
|
||||
var that = this,
|
||||
svgClone = svg.clone(true).node(),
|
||||
scaleFactor = 1;
|
||||
setTimeout(function () {
|
||||
if (platform.name === "Firefox") {
|
||||
svgClone.setAttribute("width", width);
|
||||
svgClone.setAttribute("height", height);
|
||||
}
|
||||
const hiddenSvgEl = select("body").append("div");
|
||||
hiddenSvgEl.classed("hidden-svg", true);
|
||||
hiddenSvgEl.node().appendChild(svgClone);
|
||||
|
||||
const svgCloneEl = select(".hidden-svg svg");
|
||||
svgCloneEl.select("g").attr("transform", "scale(" + scaleFactor + ")");
|
||||
svgCloneEl.select("foreignObject").remove();
|
||||
|
||||
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 canvas = document.createElement("canvas");
|
||||
canvas.id = "canvas";
|
||||
canvas.style.display = "none";
|
||||
canvas.width = svgClone.getBBox().width * scaleFactor + canvasOffset.x;
|
||||
canvas.height = svgClone.getBBox().height * scaleFactor + canvasOffset.y;
|
||||
|
||||
// Append Canvas in DOM
|
||||
select("body").node().appendChild(canvas);
|
||||
|
||||
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");
|
||||
a.download = downloadFileName;
|
||||
document.body.appendChild(a);
|
||||
ctx.drawImage(img, 50, 50, canvas.width, canvas.height);
|
||||
canvas.toBlob(function (blob) {
|
||||
if (!blob) {
|
||||
onExportLineage({ status: "failed", message: "There was an error in downloading Lineage!" });
|
||||
return;
|
||||
}
|
||||
a.href = DOMURL.createObjectURL(blob);
|
||||
if (blob.size > 10000000) {
|
||||
onExportLineage({ status: "failed", message: "The Image size is huge, please open the image in a browser!" });
|
||||
}
|
||||
a.click();
|
||||
onExportLineage({ status: "Success", message: "Successful" });
|
||||
if (platform.name === "Safari") {
|
||||
that.refreshGraphForSafari({
|
||||
edgeEl: that.$("svg g.node")
|
||||
});
|
||||
}
|
||||
}, "image/png");
|
||||
hiddenSvgEl.remove();
|
||||
canvas.remove();
|
||||
} catch (err) {
|
||||
onExportLineage({ status: "failed", message: "There was an error in downloading Lineage!" });
|
||||
}
|
||||
};
|
||||
img.src = url;
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
export default LineageUtils;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import LineageUtils from "./LineageUtils";
|
||||
import DataUtils from "./DataUtils";
|
||||
|
||||
String.prototype.trunc =
|
||||
String.prototype.trunc ||
|
||||
function(n) {
|
||||
return this.length > n ? this.substr(0, n - 1) + "..." : this;
|
||||
};
|
||||
|
||||
export { LineageUtils, DataUtils };
|
||||
|
|
@ -0,0 +1,611 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import dagreD3 from "dagre-d3";
|
||||
import { select, selection, event } from "d3-selection";
|
||||
import { curveBasis } from "d3-shape";
|
||||
import { LineageUtils, DataUtils } from "./Utils";
|
||||
import d3Tip from "d3-tip";
|
||||
|
||||
import "./styles/style.scss";
|
||||
|
||||
export default class LineageHelper {
|
||||
constructor(options) {
|
||||
this._updateOptions(options);
|
||||
const { el, manualTrigger = false } = this.options;
|
||||
if (el === undefined) {
|
||||
throw new Error("LineageHelper requires el propety to render the graph");
|
||||
}
|
||||
this.initReturnObj = {
|
||||
init: (arg) => this.init(arg),
|
||||
createGraph: (opt = {}) => this._createGraph(this.options, this.graphOptions, opt),
|
||||
clear: (arg) => this.clear(arg),
|
||||
refresh: (arg) => this.refresh(arg),
|
||||
centerAlign: (arg) => this.centerAlign(arg),
|
||||
exportLineage: (arg) => this.exportLineage(arg),
|
||||
zoomIn: (arg) => this.zoomIn(arg),
|
||||
zoomOut: (arg) => this.zoomOut(arg),
|
||||
zoom: (arg) => this.zoom(arg),
|
||||
fullScreen: (arg) => this.fullScreen(arg),
|
||||
searchNode: (arg) => this.searchNode(arg),
|
||||
removeNodeSelection: (arg) => this.removeNodeSelection(arg),
|
||||
getGraphOptions: () => this.graphOptions,
|
||||
getNode: (guid, actual) => {
|
||||
let rObj = null;
|
||||
if (actual) {
|
||||
rObj = this.actualData[guid];
|
||||
} else {
|
||||
rObj = this.g._nodes[guid];
|
||||
}
|
||||
if (rObj) {
|
||||
rObj = Object.assign({}, rObj);
|
||||
}
|
||||
return rObj;
|
||||
},
|
||||
getNodes: (guid, actual) => {
|
||||
let rObj = null;
|
||||
if (actual) {
|
||||
rObj = this.actualData;
|
||||
} else {
|
||||
rObj = this.g._nodes;
|
||||
}
|
||||
if (rObj) {
|
||||
rObj = Object.assign({}, rObj);
|
||||
}
|
||||
return rObj;
|
||||
},
|
||||
setNode: this._setGraphNode,
|
||||
setEdge: this._setGraphEdge
|
||||
};
|
||||
if (manualTrigger === false) {
|
||||
this.init();
|
||||
}
|
||||
return this.initReturnObj;
|
||||
}
|
||||
/**
|
||||
* [updateOptions get the options from user and appedn add it in this,option context]
|
||||
* @param {[Object]} options [lib options from user]
|
||||
* @return {[null]} [null]
|
||||
*/
|
||||
_updateOptions(options) {
|
||||
this.options = {};
|
||||
Object.assign(this.options, { filterObj: { isProcessHideCheck: false, isDeletedEntityHideCheck: false } }, options);
|
||||
}
|
||||
/**
|
||||
* [init Start the graph build process]
|
||||
* @return {[null]} [null]
|
||||
*/
|
||||
init() {
|
||||
const { data = {} } = this.options;
|
||||
if (data.baseEntityGuid) {
|
||||
this.guid = data.baseEntityGuid;
|
||||
}
|
||||
// Call the initializeGraph method to initlize dagreD3 graphlib
|
||||
this._initializeGraph();
|
||||
this._initGraph();
|
||||
}
|
||||
/**
|
||||
* [clear Allows user to clear the graph refrence and dom]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
clear() {
|
||||
if (!this.options.el) {
|
||||
this.svg.remove();
|
||||
this.svg = null;
|
||||
}
|
||||
this.g = null;
|
||||
this.graphOptions = {};
|
||||
}
|
||||
/**
|
||||
* [centerAlign Allows user to center the lineage position, without rerender]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
centerAlign(opt = {}) {
|
||||
var svgGroupEl = this.svg.select("g"),
|
||||
edgePathEl = svgGroupEl.selectAll("g.edgePath");
|
||||
LineageUtils.centerNode({
|
||||
...this.graphOptions,
|
||||
svgGroupEl,
|
||||
edgePathEl,
|
||||
...opt
|
||||
});
|
||||
}
|
||||
/**
|
||||
* [zoomIn description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
zoomIn(opt = {}) {
|
||||
LineageUtils.zoomIn({ ...this.graphOptions, ...opt });
|
||||
}
|
||||
/**
|
||||
* [zoomOut description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
zoomOut(opt = {}) {
|
||||
LineageUtils.zoomOut({ ...this.graphOptions, ...opt });
|
||||
}
|
||||
/**
|
||||
* [zoom description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
zoom(opt = {}) {
|
||||
LineageUtils.zoom({ ...this.graphOptions, ...opt });
|
||||
}
|
||||
/**
|
||||
* [refresh Allows user to rerender the lineage]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
refresh() {
|
||||
this.clear();
|
||||
this._initializeGraph();
|
||||
this._initGraph({ refresh: true });
|
||||
}
|
||||
/**
|
||||
* [removeNodeSelection description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
removeNodeSelection() {
|
||||
this.svg.selectAll("g.node>circle").classed("node-detail-highlight", false);
|
||||
}
|
||||
/**
|
||||
* [searchNode description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
searchNode({ guid, onSearchNode }) {
|
||||
this.svg.selectAll(".serach-rect").remove();
|
||||
this.centerAlign({
|
||||
guid: guid,
|
||||
onCenterZoomed: function (opts) {
|
||||
const { selectedNodeEl } = opts;
|
||||
selectedNodeEl.select(".label").attr("stroke", "#316132");
|
||||
selectedNodeEl.select("circle").classed("wobble", true);
|
||||
selectedNodeEl
|
||||
.insert("rect", "circle")
|
||||
.attr("class", "serach-rect")
|
||||
.attr("x", -50)
|
||||
.attr("y", -27.5)
|
||||
.attr("width", 100)
|
||||
.attr("height", 55);
|
||||
if (onSearchNode && typeof onSearchNode === "function") {
|
||||
onSearchNode(opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [exportLineage description]
|
||||
* @param {Object} options [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
exportLineage(options = {}) {
|
||||
let downloadFileName = options.downloadFileName;
|
||||
if (downloadFileName === undefined) {
|
||||
let node = this.g._nodes[this.guid];
|
||||
if (node && node.attributes) {
|
||||
downloadFileName = `${node.attributes.qualifiedName || node.attributes.name || "lineage_export"}.png`;
|
||||
} else {
|
||||
downloadFileName = "lineage_export.png";
|
||||
}
|
||||
}
|
||||
|
||||
LineageUtils.saveSvg({
|
||||
...this.graphOptions,
|
||||
downloadFileName: downloadFileName,
|
||||
onExportLineage: (opt) => {
|
||||
if (options.onExportLineage) {
|
||||
onExportLineage(opt);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* [fullScreen description]
|
||||
* @param {Object} options.el } [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
fullScreen({ el } = {}) {
|
||||
if (el === undefined) {
|
||||
throw new Error("LineageHelper requires el propety to apply fullScreen class");
|
||||
}
|
||||
const fullScreenEl = select(el);
|
||||
if (fullScreenEl.classed("fullscreen-mode")) {
|
||||
fullScreenEl.classed("fullscreen-mode", false);
|
||||
return false;
|
||||
} else {
|
||||
fullScreenEl.classed("fullscreen-mode", true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* [_getValueFromUser description]
|
||||
* @param {[type]} ref [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_getValueFromUser(ref) {
|
||||
if (ref !== undefined) {
|
||||
if (typeof ref === "function") {
|
||||
return ref();
|
||||
} else {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* [initializeGraph initlize the dagreD3 graphlib]
|
||||
* @return {[null]} [null]
|
||||
*/
|
||||
_initializeGraph() {
|
||||
const { width = "100%", height = "100%", el } = this.options;
|
||||
|
||||
// Append the svg using d3.
|
||||
this.svg = select(el);
|
||||
|
||||
if (!(el instanceof SVGElement)) {
|
||||
this.svg = this.svg
|
||||
.append("svg")
|
||||
.attr("xmlns", "http://www.w3.org/2000/svg")
|
||||
.attr(" xmlns:xlink", "http://www.w3.org/1999/xlink")
|
||||
.attr("version", "1.1")
|
||||
.attr("width", width)
|
||||
.attr("height", height);
|
||||
}
|
||||
// initlize the dagreD3 graphlib
|
||||
this.g = new dagreD3.graphlib.Graph()
|
||||
.setGraph(
|
||||
Object.assign(
|
||||
{
|
||||
nodesep: 50,
|
||||
ranksep: 90,
|
||||
rankdir: "LR",
|
||||
marginx: 20,
|
||||
marginy: 20,
|
||||
transition: function transition(selection) {
|
||||
return selection.transition().duration(500);
|
||||
}
|
||||
},
|
||||
this.options.dagreOptions
|
||||
)
|
||||
)
|
||||
.setDefaultEdgeLabel(function () {
|
||||
return {};
|
||||
});
|
||||
|
||||
// Create graphOptions for common use
|
||||
var svgRect = this.svg.node().getBoundingClientRect();
|
||||
this.actualData = {};
|
||||
this.graphOptions = {
|
||||
svg: this.svg,
|
||||
g: this.g,
|
||||
dagreD3: dagreD3,
|
||||
guid: this.guid,
|
||||
width: this.options.width || svgRect.width,
|
||||
height: this.options.height || svgRect.height
|
||||
};
|
||||
}
|
||||
/**
|
||||
* [_initGraph description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_initGraph({ refresh } = {}) {
|
||||
if (this.svg) {
|
||||
this.svg.select("g").remove();
|
||||
}
|
||||
let filterObj = this.options.filterObj;
|
||||
if (this.options.getFilterObj) {
|
||||
let filterObjVal = this.options.getFilterObj();
|
||||
if (filterObjVal !== undefined || filterObjVal !== null) {
|
||||
if (typeof filterObjVal === "object") {
|
||||
filterObj = filterObjVal;
|
||||
} else {
|
||||
throw new Error("getFilterObj expect return type `object`,`null` or `Undefined`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.setDataManually === true) {
|
||||
return;
|
||||
} else if (this.options.data === undefined || (this.options.data && this.options.data.relations.length === 0)) {
|
||||
if (this.options.beforeRender) {
|
||||
this.options.beforeRender();
|
||||
}
|
||||
this.svg
|
||||
.append("text")
|
||||
.attr("x", "50%")
|
||||
.attr("y", "50%")
|
||||
.attr("alignment-baseline", "middle")
|
||||
.attr("text-anchor", "middle")
|
||||
.text("No lineage data found");
|
||||
if (this.options.afterRender) {
|
||||
this.options.afterRender();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return DataUtils.generateData({
|
||||
...this.options,
|
||||
filterObj: filterObj,
|
||||
...this.graphOptions,
|
||||
setGraphNode: this._setGraphNode,
|
||||
setGraphEdge: this._setGraphEdge
|
||||
}).then((graphObj) => {
|
||||
this._createGraph(this.options, this.graphOptions, { refresh });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [description]
|
||||
* @param {[type]} guid [description]
|
||||
* @param {[type]} nodeData [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_setGraphNode = (guid, nodeData) => {
|
||||
this.actualData[guid] = Object.assign({}, nodeData);
|
||||
this.g.setNode(guid, nodeData);
|
||||
};
|
||||
|
||||
/**
|
||||
* [description]
|
||||
* @param {[type]} fromGuid [description]
|
||||
* @param {[type]} toGuid [description]
|
||||
* @param {[type]} opts [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_setGraphEdge = (fromGuid, toGuid, opts) => {
|
||||
this.g.setEdge(fromGuid, toGuid, {
|
||||
curve: curveBasis,
|
||||
...opts
|
||||
});
|
||||
};
|
||||
/**
|
||||
* [_createGraph description]
|
||||
* @param {Object} options.data [description]
|
||||
* @param {Boolean} isShowTooltip [description]
|
||||
* @param {Boolean} isShowHoverPath [description]
|
||||
* @param {[type]} onLabelClick [description]
|
||||
* @param {[type]} onPathClick [description]
|
||||
* @param {[type]} onNodeClick } [description]
|
||||
* @param {[type]} graphOptions [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
_createGraph(
|
||||
{ data = {}, imgBasePath, isShowTooltip, isShowHoverPath, onLabelClick, onPathClick, onNodeClick, zoom, fitToScreen },
|
||||
graphOptions,
|
||||
{ refresh }
|
||||
) {
|
||||
if (this.options.beforeRender) {
|
||||
this.options.beforeRender();
|
||||
}
|
||||
const that = this,
|
||||
{ svg, g, width, height } = graphOptions;
|
||||
|
||||
if (svg instanceof selection === false) {
|
||||
throw new Error("svg is not initialized or something went wrong while creatig graph instance");
|
||||
return;
|
||||
}
|
||||
if (g._nodes === undefined || g._nodes.length === 0) {
|
||||
svg.html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>');
|
||||
return;
|
||||
}
|
||||
|
||||
g.nodes().forEach(function (v) {
|
||||
var node = g.node(v);
|
||||
// Round the corners of the nodes
|
||||
if (node) {
|
||||
node.rx = node.ry = 5;
|
||||
}
|
||||
});
|
||||
|
||||
svg.attr("viewBox", "0 0 " + width + " " + height).attr("enable-background", "new 0 0 " + width + " " + height);
|
||||
var svgGroupEl = svg.append("g");
|
||||
|
||||
// Append defs
|
||||
var defsEl = svg.append("defs");
|
||||
|
||||
// Create the renderer
|
||||
var render = new dagreD3.render();
|
||||
// Add our custom arrow (a hollow-point)
|
||||
render.arrows().arrowPoint = function () {
|
||||
return LineageUtils.arrowPointRender(...arguments, { ...graphOptions });
|
||||
};
|
||||
// Render custom img inside shape
|
||||
render.shapes().img = function () {
|
||||
return LineageUtils.imgShapeRender(...arguments, {
|
||||
...graphOptions,
|
||||
imgBasePath: that._getValueFromUser(imgBasePath),
|
||||
defsEl
|
||||
});
|
||||
};
|
||||
|
||||
var tooltip = d3Tip()
|
||||
.attr("class", "d3-tip")
|
||||
.offset([10, 0])
|
||||
.html((d) => {
|
||||
var value = g.node(d);
|
||||
var htmlStr = "";
|
||||
if (value.id !== this.guid) {
|
||||
htmlStr = "<h5 style='text-align: center;'>" + (value.isLineage ? "Lineage" : "Impact") + "</h5>";
|
||||
}
|
||||
htmlStr += "<h5 class='text-center'><span style='color:#359f89'>" + value.toolTipLabel + "</span></h5> ";
|
||||
if (value.typeName) {
|
||||
htmlStr += "<h5 class='text-center'><span>(" + value.typeName + ")</span></h5> ";
|
||||
}
|
||||
if (value.queryText) {
|
||||
htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> ";
|
||||
}
|
||||
return "<div class='tip-inner-scroll'>" + htmlStr + "</div>";
|
||||
});
|
||||
|
||||
svg.call(tooltip);
|
||||
|
||||
// if (platform.name !== "IE") {
|
||||
// this.$(".fontLoader").hide();
|
||||
// }
|
||||
|
||||
render(svgGroupEl, g);
|
||||
|
||||
//change text postion
|
||||
svgGroupEl
|
||||
.selectAll("g.nodes g.label")
|
||||
.attr("transform", "translate(2,-35)")
|
||||
.on("mouseenter", function (d) {
|
||||
event.preventDefault();
|
||||
select(this).classed("highlight", true);
|
||||
})
|
||||
.on("mouseleave", function (d) {
|
||||
event.preventDefault();
|
||||
select(this).classed("highlight", false);
|
||||
})
|
||||
.on("click", function (d) {
|
||||
event.preventDefault();
|
||||
if (onLabelClick && typeof onLabelClick === "function") {
|
||||
onLabelClick({ clickedData: d });
|
||||
}
|
||||
tooltip.hide(d);
|
||||
});
|
||||
|
||||
svgGroupEl
|
||||
.selectAll("g.nodes g.node circle")
|
||||
.on("mouseenter", function (d, index, element) {
|
||||
that.activeNode = true;
|
||||
var matrix = this.getScreenCTM().translate(+this.getAttribute("cx"), +this.getAttribute("cy"));
|
||||
that.svg.selectAll(".node").classed("active", false);
|
||||
select(this).classed("active", true);
|
||||
if (that._getValueFromUser(isShowTooltip)) {
|
||||
var direction = LineageUtils.getToolTipDirection({ el: this });
|
||||
tooltip.direction(direction).show(d, this);
|
||||
}
|
||||
if (that._getValueFromUser(isShowHoverPath) === false) {
|
||||
return;
|
||||
}
|
||||
LineageUtils.onHoverFade({
|
||||
opacity: 0.3,
|
||||
mouseenter: true,
|
||||
hoveredNode: d,
|
||||
...graphOptions
|
||||
});
|
||||
})
|
||||
.on("mouseleave", function (d) {
|
||||
that.activeNode = false;
|
||||
var nodeEL = this;
|
||||
setTimeout(function (argument) {
|
||||
if (!(that.activeTip || that.activeNode)) {
|
||||
select(nodeEL).classed("active", false);
|
||||
if (that._getValueFromUser(isShowTooltip)) {
|
||||
tooltip.hide(d);
|
||||
}
|
||||
}
|
||||
}, 150);
|
||||
if (that._getValueFromUser(isShowHoverPath) === false) {
|
||||
return;
|
||||
}
|
||||
LineageUtils.onHoverFade({
|
||||
mouseenter: false,
|
||||
hoveredNode: d,
|
||||
...graphOptions
|
||||
});
|
||||
})
|
||||
.on("click", function (d) {
|
||||
if (event.defaultPrevented) return; // ignore drag
|
||||
event.preventDefault();
|
||||
tooltip.hide(d);
|
||||
svg.selectAll("g.node>circle").classed("node-detail-highlight", false);
|
||||
select(this).classed("node-detail-highlight", true);
|
||||
if (onNodeClick && typeof onNodeClick === "function") {
|
||||
onNodeClick({ clickedData: d, el: this });
|
||||
}
|
||||
});
|
||||
|
||||
// Bind event on edgePath
|
||||
var edgePathEl = svgGroupEl.selectAll("g.edgePath");
|
||||
edgePathEl.selectAll("path.path").on("click", function (d) {
|
||||
if (onPathClick && typeof onPathClick === "function") {
|
||||
var pathRelationObj = data.relations.find(function (obj) {
|
||||
if (obj.fromEntityId === d.v && obj.toEntityId === d.w) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
onPathClick({ pathRelationObj, clickedData: d });
|
||||
}
|
||||
});
|
||||
|
||||
// tooltip hover handle to fix node hover conflict
|
||||
// select("body").on("mouseover", ".d3-tip", function(el) {
|
||||
// that.activeTip = true;
|
||||
// });
|
||||
// select("body").on("mouseleave", ".d3-tip", function(el) {
|
||||
// that.activeTip = false;
|
||||
// svg.selectAll(".node").classed("active", false);
|
||||
// //tooltip.hide();
|
||||
// });
|
||||
|
||||
// Center the graph
|
||||
if (zoom !== false) {
|
||||
LineageUtils.centerNode({
|
||||
...graphOptions,
|
||||
fitToScreen,
|
||||
svgGroupEl,
|
||||
edgePathEl
|
||||
});
|
||||
}
|
||||
|
||||
// if (platform.name === "IE") {
|
||||
// LineageUtils.refreshGraphForIE({
|
||||
// edgeEl: this.$("svg .edgePath")
|
||||
// });
|
||||
// }
|
||||
|
||||
LineageUtils.dragNode({
|
||||
...graphOptions,
|
||||
edgePathEl
|
||||
});
|
||||
|
||||
if (refresh !== true) {
|
||||
this._addLegend();
|
||||
}
|
||||
|
||||
if (this.options.afterRender) {
|
||||
this.options.afterRender();
|
||||
}
|
||||
}
|
||||
_addLegend() {
|
||||
if (this.options.legends === false) {
|
||||
return;
|
||||
}
|
||||
var container = select(this.options.legendsEl || this.options.el)
|
||||
.insert("div", ":first-child")
|
||||
.classed("legends", true);
|
||||
|
||||
let span = container.append("span").style("color", "#fb4200");
|
||||
span.append("i").classed("fa fa-circle-o fa-fw", true);
|
||||
span.append("span").html("Current Entity");
|
||||
|
||||
span = container.append("span").style("color", "#686868");
|
||||
span.append("i").classed("fa fa-hourglass-half fa-fw", true);
|
||||
span.append("span").html("In Progress");
|
||||
|
||||
span = container.append("span").style("color", "#df9b00");
|
||||
span.append("i").classed("fa fa-long-arrow-right fa-fw", true);
|
||||
span.append("span").html("Lineage");
|
||||
|
||||
span = container.append("span").style("color", "#fb4200");
|
||||
span.append("i").classed("fa fa-long-arrow-right fa-fw", true);
|
||||
span.append("span").html("Impact");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// 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.
|
||||
|
||||
//fonts
|
||||
$font_0: Source Sans Pro;
|
||||
$font_1: sans-serif;
|
||||
|
||||
//Colors
|
||||
|
||||
$white: #fff;
|
||||
$dark_gray: #666;
|
||||
$light_gray: #e8e8e8;
|
||||
$black_80: rgba(0, 0, 0, 0.8);
|
||||
|
||||
$color_mountain_mist_approx: #999;
|
||||
$color_keppel_approx: #37bb9b;
|
||||
$color_suva_gray_approx: #868686;
|
||||
$color_havelock_blue_approx: #4a90e2;
|
||||
$color_celeste_approx: #ccc;
|
||||
$color_bright_turquoise_approx: #00ffd0;
|
||||
$color_jungle_green_approx: #38bb9b;
|
||||
$delete_link: #bb5838;
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
// 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.
|
||||
|
||||
/* graph.scss */
|
||||
|
||||
.node {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 10px;
|
||||
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 {
|
||||
fill: $color_suva_gray_approx;
|
||||
|
||||
&.highlight {
|
||||
cursor: pointer;
|
||||
fill: $color_havelock_blue_approx;
|
||||
text-decoration: underline;
|
||||
|
||||
tspan {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
circle {
|
||||
-moz-transition: all 0.3s;
|
||||
-webkit-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
stroke-width: 1.5px;
|
||||
|
||||
&.node-detail-highlight {
|
||||
stroke: $color_havelock_blue_approx;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
&.nodeImage {
|
||||
&.green:hover {
|
||||
stroke: #ffb203;
|
||||
}
|
||||
|
||||
&.blue:hover {
|
||||
stroke: #4b91e2;
|
||||
}
|
||||
|
||||
&.currentNode {
|
||||
stroke: #fb4200;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
-moz-transform: scale(1.4);
|
||||
-webkit-transform: scale(1.4);
|
||||
transform: scale(1.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
circle {
|
||||
-moz-transform: scale(1.4);
|
||||
-webkit-transform: scale(1.4);
|
||||
transform: scale(1.4);
|
||||
|
||||
&.nodeImage {
|
||||
&.green {
|
||||
stroke: #ffb203;
|
||||
}
|
||||
|
||||
&.blue {
|
||||
stroke: #4b91e2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.legends {
|
||||
> span {
|
||||
margin-right: 8px;
|
||||
font-family: $font_0;
|
||||
}
|
||||
}
|
||||
|
||||
svg.hover {
|
||||
g.node {
|
||||
opacity: 0.1 !important;
|
||||
}
|
||||
|
||||
g.edgePath {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
g.node.hover-active-node,
|
||||
g.edgePath.hover-active-path {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.invisible {
|
||||
.node circle {
|
||||
transition: all 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.edgePath {
|
||||
.path {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
fill: none;
|
||||
stroke: $color_celeste_approx;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.d3-tip {
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
padding: 12px;
|
||||
background: $black_80;
|
||||
color: $white;
|
||||
z-index: 999;
|
||||
max-width: 300px; //Instead of the line below you could use @include border-radius($radius, $vertical-radius)
|
||||
border-radius: 2px;
|
||||
|
||||
.tip-inner-scroll {
|
||||
overflow: auto;
|
||||
max-height: 300px;
|
||||
h5 {
|
||||
margin: 7px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Creates a small triangle extender for the tooltip */
|
||||
&:after {
|
||||
box-sizing: border-box;
|
||||
display: inline;
|
||||
font-size: 10px;
|
||||
width: 100%;
|
||||
line-height: 1;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* Nrthward tooltips */
|
||||
&.n:after {
|
||||
content: "\25BC";
|
||||
margin: -1px 0 0 0;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Eastward tooltips */
|
||||
&.e:after {
|
||||
content: "\25C0";
|
||||
margin: -4px 0 0 0;
|
||||
top: 50%;
|
||||
left: -8px;
|
||||
}
|
||||
|
||||
/* Southward tooltips */
|
||||
&.s:after {
|
||||
content: "\25B2";
|
||||
margin: 0 0 1px 0;
|
||||
top: -8px;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Westward tooltips */
|
||||
&.w:after {
|
||||
content: "\25B6";
|
||||
margin: -4px 0 0 -1px;
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
g.type-TK > rect {
|
||||
fill: $color_bright_turquoise_approx;
|
||||
}
|
||||
|
||||
.fullscreen-mode {
|
||||
position: fixed;
|
||||
height: 100% !important;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
right: 0;
|
||||
padding: 0 !important;
|
||||
z-index: 9999;
|
||||
overflow: hidden !important;
|
||||
|
||||
.resizeGraph {
|
||||
position: fixed;
|
||||
height: 100% !important;
|
||||
|
||||
.ui-resizable-handle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.hidden-svg {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@-webkit-keyframes blink {
|
||||
from {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// 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.
|
||||
|
||||
@import "./__varibale.scss";
|
||||
@import "./graph.scss";
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
|
||||
const distPath = path.resolve(__dirname, "dist");
|
||||
|
||||
const node_env = process.env.NODE_ENV ? process.env.NODE_ENV : 'production';
|
||||
|
||||
const config = {
|
||||
mode: node_env,
|
||||
entry: "./src/index.js",
|
||||
output: {
|
||||
library: "LineageHelper",
|
||||
libraryTarget: "umd",
|
||||
path: distPath,
|
||||
filename: "index.js"
|
||||
},
|
||||
plugins: [new MiniCssExtractPlugin({ filename: "styles.css" })],
|
||||
externals: {
|
||||
//don't bundle the 'react' npm package with our bundle.js
|
||||
//but get it from a global 'React' variable
|
||||
d3: "d3",
|
||||
"dagre-d3": "dagreD3",
|
||||
platform: "platform",
|
||||
dagre: "dagre",
|
||||
graphlib: "graphlib"
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js$/,
|
||||
exclude: /(node_modules|bower_components)/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: ["@babel/preset-env"],
|
||||
plugins: ["transform-class-properties"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.s[ac]ss$/i,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
// Translates CSS into CommonJS
|
||||
"css-loader",
|
||||
// Compiles Sass to CSS
|
||||
"sass-loader"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
config.devtool = "inline-source-map";
|
||||
}
|
||||
module.exports = config;
|
||||
|
|
@ -128,10 +128,20 @@ require.config({
|
|||
'deps': ['d3'],
|
||||
'exports': ['d3-tip']
|
||||
},
|
||||
'LineageHelper': {
|
||||
'deps': ['d3'],
|
||||
},
|
||||
'dagreD3': {
|
||||
'deps': ['d3'],
|
||||
'exports': ['dagreD3']
|
||||
},
|
||||
'nvd3': {
|
||||
'deps': ['d3']
|
||||
},
|
||||
'sparkline': {
|
||||
'deps': ['jquery'],
|
||||
'exports': ['sparkline']
|
||||
},
|
||||
'pnotify': {
|
||||
'exports': ['pnotify']
|
||||
},
|
||||
|
|
@ -150,13 +160,6 @@ require.config({
|
|||
'moment': {
|
||||
'exports': ['moment']
|
||||
},
|
||||
'nvd3': {
|
||||
'deps': ['d3']
|
||||
},
|
||||
'sparkline': {
|
||||
'deps': ['jquery'],
|
||||
'exports': ['sparkline']
|
||||
},
|
||||
'jstree': {
|
||||
'deps': ['jquery']
|
||||
},
|
||||
|
|
@ -183,12 +186,15 @@ require.config({
|
|||
'asBreadcrumbs': 'libs/jquery-asBreadcrumbs/js/jquery-asBreadcrumbs.min',
|
||||
'd3': 'libs/d3/d3.min',
|
||||
'd3-tip': 'libs/d3/index',
|
||||
'LineageHelper': 'external_lib/atlas-lineage/dist/index',
|
||||
'dagreD3': 'libs/dagre-d3/dagre-d3.min',
|
||||
'nvd3': 'libs/nvd3/nv.d3.min',
|
||||
'sparkline': 'libs/sparkline/jquery.sparkline.min',
|
||||
'tmpl': 'templates',
|
||||
'requirejs.text': 'libs/requirejs-text/text',
|
||||
'handlebars': 'external_lib/require-handlebars-plugin/js/handlebars',
|
||||
'hbs': 'external_lib/require-handlebars-plugin/js/hbs',
|
||||
'i18nprecompile': 'external_lib/require-handlebars-plugin/js/i18nprecompile',
|
||||
'dagreD3': 'libs/dagre-d3/dagre-d3.min',
|
||||
'select2': 'libs/select2/select2.full.min',
|
||||
'backgrid-select-all': 'libs/backgrid-select-all/backgrid-select-all.min',
|
||||
'moment': 'libs/moment/js/moment.min',
|
||||
|
|
@ -201,8 +207,6 @@ require.config({
|
|||
'platform': 'libs/platform/platform',
|
||||
'query-builder': 'libs/jQueryQueryBuilder/js/query-builder.standalone.min',
|
||||
'daterangepicker': 'libs/bootstrap-daterangepicker/js/daterangepicker',
|
||||
'nvd3': 'libs/nvd3/nv.d3.min',
|
||||
'sparkline': 'libs/sparkline/jquery.sparkline.min',
|
||||
'table-dragger': 'libs/table-dragger/table-dragger',
|
||||
'jstree': 'libs/jstree/jstree.min',
|
||||
'jquery-steps': 'libs/jquery-steps/jquery.steps.min',
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
<li role="businessMetadata" class="tab active"><a href="#tab-businessMetadata" aria-controls="tab-businessMetadata" role="tab" data-toggle="tab">Business Metadata</a></li>
|
||||
<li role="enum"><a href="#tab-enum" aria-controls="tab-enum" role="tab" data-toggle="tab">Enumerations</a></li>
|
||||
<li role="audit"><a href="#tab-audit" aria-controls="tab-audit" role="tab" data-toggle="tab">Audits</a></li>
|
||||
<li role="typeSystem"><a href="#tab-typeSystem" aria-controls="tab-typeSystem" role="tab" data-toggle="tab">Type System</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -36,5 +37,9 @@
|
|||
<div id="r_adminTableLayoutView">
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-typeSystem" role="typeSystem" class="tab-pane animated fadeIn" style="position: relative;">
|
||||
<div id="r_typeSystemTreeLayoutView">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -100,7 +100,9 @@
|
|||
</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>
|
||||
<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>
|
||||
|
|
@ -109,11 +111,17 @@
|
|||
<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>
|
||||
<button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom In" data-id="zoom-in">
|
||||
<i class="fa fa-search-plus"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom Out" data-id="zoom-out">
|
||||
<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>
|
||||
<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">
|
||||
|
|
@ -123,7 +131,7 @@
|
|||
<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 bold-key'>
|
||||
<table class="table bold-key">
|
||||
<tbody data-id="nodeDetailTable"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -131,11 +139,7 @@
|
|||
<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"></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>
|
||||
<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 class="legends pull-left" style="height: 25px; padding: 2px;"></div>
|
||||
<div class="svg" style="height: 100%; width: 100%"></div>
|
||||
</div>
|
||||
<div class="hidden-svg"></div>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<!--
|
||||
* 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.
|
||||
-->
|
||||
<div id="typeSystemTreeViewPage" data-id="typeSystemTreeViewPage" class="systemTypeTree" style="height: calc(100vh - 180px); width: 100%; position: relative;overflow: hidden;">
|
||||
<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 bold-key">
|
||||
<tbody data-id="nodeDetailTable"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fontLoader">
|
||||
<i class="fa fa-refresh fa-spin-custom"></i>
|
||||
</div>
|
||||
<div class="box-panel filter-box">
|
||||
<div class="header clearfix">
|
||||
<h4>Filters</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="form-group text-left col-sm-12">
|
||||
<select data-id="filterServiceType"></select>
|
||||
</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="graph-button-group pull-right">
|
||||
<div>
|
||||
<button data-id="reset" class="btn btn-action btn-gray btn-sm" title="Realign Lineage">
|
||||
<i class="fa fa-retweet"></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="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" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom In" data-id="zoom-in">
|
||||
<i class="fa fa-search-plus"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-action btn-gray btn-sm lineageZoomButton" title="Zoom Out" data-id="zoom-out">
|
||||
<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>
|
||||
<svg class="main" width="100%" height="100%">
|
||||
</svg>
|
||||
<!-- <div id="mini" class="mini-map-type-system">
|
||||
<svg class="mini" width="100%" height="100%">
|
||||
</svg>
|
||||
</div> -->
|
||||
</div>
|
||||
|
|
@ -143,7 +143,7 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
|
|||
id = data.guid;
|
||||
}
|
||||
if (value.length > 0) {
|
||||
scope.$('td div[data-id="' + id + '"]').html('<a href="#!/detailPage/' + id + '">' + getValue(value, key) + '</a>');
|
||||
scope.$('td div[data-id="' + id + '"]').html('<a href="#!/detailPage/' + id + '">' + getValue(value) + '</a>');
|
||||
} else {
|
||||
scope.$('td div[data-id="' + id + '"]').html('<a href="#!/detailPage/' + id + '">' + _.escape(id) + '</a>');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ define(['require',
|
|||
regions: {
|
||||
RBusinessMetadataTableLayoutView: "#r_businessMetadataTableLayoutView",
|
||||
REnumTableLayoutView: '#r_enumTableLayoutView',
|
||||
RAdminTableLayoutView: '#r_adminTableLayoutView'
|
||||
RAdminTableLayoutView: '#r_adminTableLayoutView',
|
||||
RTypeSystemTreeLayoutView: '#r_typeSystemTreeLayoutView',
|
||||
|
||||
},
|
||||
|
||||
/** ui selector cache */
|
||||
|
|
@ -81,6 +83,7 @@ define(['require',
|
|||
bindEvents: function() {
|
||||
this.renderEnumLayoutView();
|
||||
this.renderAdminLayoutView();
|
||||
this.renderTypeSystemTreeLayoutView();
|
||||
},
|
||||
onRender: function() {
|
||||
this.renderBusinessMetadataLayoutView();
|
||||
|
|
@ -112,6 +115,15 @@ define(['require',
|
|||
});
|
||||
that.RAdminTableLayoutView.show(view);
|
||||
});
|
||||
},
|
||||
renderTypeSystemTreeLayoutView: function(obj) {
|
||||
var that = this;
|
||||
require(["views/graph/TypeSystemTreeView"], function(TypeSystemTreeView) {
|
||||
var view = new TypeSystemTreeView({
|
||||
entityDefCollection: that.entityDefCollection
|
||||
});
|
||||
that.RTypeSystemTreeLayoutView.show(view);
|
||||
});
|
||||
}
|
||||
});
|
||||
return AdministratorLayoutView;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ define(['require',
|
|||
'collection/VLineageList',
|
||||
'models/VEntity',
|
||||
'utils/Utils',
|
||||
'views/graph/LineageUtils',
|
||||
'LineageHelper',
|
||||
'd3',
|
||||
'dagreD3',
|
||||
'd3-tip',
|
||||
'utils/Enums',
|
||||
|
|
@ -31,7 +32,7 @@ define(['require',
|
|||
'utils/CommonViewFunction',
|
||||
'platform',
|
||||
'jquery-ui'
|
||||
], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, LineageUtils, dagreD3, d3Tip, Enums, UrlLinks, Globals, CommonViewFunction, platform) {
|
||||
], function(require, Backbone, LineageLayoutViewtmpl, VLineageList, VEntity, Utils, LineageHelper, d3, dagreD3, d3Tip, Enums, UrlLinks, Globals, CommonViewFunction, platform) {
|
||||
'use strict';
|
||||
|
||||
var LineageLayoutView = Backbone.Marionette.LayoutView.extend(
|
||||
|
|
@ -65,7 +66,9 @@ define(['require',
|
|||
showOnlyHoverPath: '[data-id="showOnlyHoverPath"]',
|
||||
showTooltip: '[data-id="showTooltip"]',
|
||||
saveSvg: '[data-id="saveSvg"]',
|
||||
resetLineage: '[data-id="resetLineage"]'
|
||||
resetLineage: '[data-id="resetLineage"]',
|
||||
onZoomIn: '[data-id="zoom-in"]',
|
||||
onZoomOut: '[data-id="zoom-out"]'
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
|
|
@ -86,6 +89,8 @@ define(['require',
|
|||
events["click " + this.ui.searchToggler] = 'onClickSearchToggler';
|
||||
events["click " + this.ui.saveSvg] = 'onClickSaveSvg';
|
||||
events["click " + this.ui.resetLineage] = 'onClickResetLineage';
|
||||
events["click " + this.ui.onZoomIn] = 'onClickZoomIn';
|
||||
events["click " + this.ui.onZoomOut] = 'onClickZoomOut';
|
||||
return events;
|
||||
},
|
||||
|
||||
|
|
@ -96,7 +101,6 @@ define(['require',
|
|||
initialize: function(options) {
|
||||
_.extend(this, _.pick(options, 'processCheck', 'guid', 'entity', 'entityName', 'entityDefCollection', 'actionCallBack', 'fetchCollection', 'attributeDefs'));
|
||||
this.collection = new VLineageList();
|
||||
this.lineageData = null;
|
||||
this.typeMap = {};
|
||||
this.apiGuid = {};
|
||||
this.edgeCall;
|
||||
|
|
@ -109,42 +113,18 @@ define(['require',
|
|||
selectedNode: ''
|
||||
}
|
||||
},
|
||||
initializeGraph: function() {
|
||||
this.g = {};
|
||||
this.g = new dagreD3.graphlib.Graph()
|
||||
.setGraph({
|
||||
nodesep: 50,
|
||||
ranksep: 90,
|
||||
rankdir: "LR",
|
||||
marginx: 20,
|
||||
marginy: 20,
|
||||
transition: function transition(selection) {
|
||||
return selection.transition().duration(500);
|
||||
}
|
||||
})
|
||||
.setDefaultEdgeLabel(function() {
|
||||
return {};
|
||||
});
|
||||
},
|
||||
onRender: function() {
|
||||
var that = this;
|
||||
this.ui.searchToggler.prop("disabled", true);
|
||||
this.$graphButtonsEl = this.$(".graph-button-group button,select[data-id='selectDepth']")
|
||||
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();
|
||||
}
|
||||
if (this.processCheck) {
|
||||
this.hideCheckForProcess();
|
||||
}
|
||||
this.initializeGraph();
|
||||
//this.initializeGraph();
|
||||
this.ui.selectDepth.select2({
|
||||
data: _.sortBy([3, 6, 9, 12, 15, 18, 21]),
|
||||
tags: true,
|
||||
|
|
@ -175,21 +155,13 @@ define(['require',
|
|||
},
|
||||
onCheckUnwantedEntity: function(e) {
|
||||
var that = this;
|
||||
this.initializeGraph();
|
||||
//this.initializeGraph();
|
||||
if ($(e.target).data("id") === "checkHideProcess") {
|
||||
this.filterObj.isProcessHideCheck = e.target.checked;
|
||||
} else {
|
||||
this.filterObj.isDeletedEntityHideCheck = e.target.checked;
|
||||
}
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl
|
||||
});
|
||||
this.generateData(this.lineageData).then(function() {
|
||||
that.createGraph();
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl
|
||||
});
|
||||
});
|
||||
this.LineageHelperRef.refresh();
|
||||
},
|
||||
toggleBoxPanel: function(options) {
|
||||
var el = options && options.el,
|
||||
|
|
@ -201,6 +173,24 @@ define(['require',
|
|||
}
|
||||
this.$('circle.node-detail-highlight').removeClass("node-detail-highlight");
|
||||
},
|
||||
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');
|
||||
}
|
||||
},
|
||||
toggleDisableState: function(options) {
|
||||
var el = options.el,
|
||||
disabled = options.disabled;
|
||||
if (el && el.prop) {
|
||||
if (disabled) {
|
||||
el.prop("disabled", disabled);
|
||||
} else {
|
||||
el.prop("disabled", !el.prop("disabled"));
|
||||
}
|
||||
}
|
||||
},
|
||||
onClickNodeToggler: function(options) {
|
||||
this.toggleBoxPanel({ el: this.$('.lineage-node-detail'), nodeDetailToggler: true });
|
||||
},
|
||||
|
|
@ -214,17 +204,30 @@ define(['require',
|
|||
this.toggleBoxPanel({ el: this.ui.searchBox });
|
||||
},
|
||||
onSelectDepthChange: function(e, options) {
|
||||
this.initializeGraph();
|
||||
//this.initializeGraph();
|
||||
this.filterObj.depthCount = e.currentTarget.value;
|
||||
this.fetchGraphData({ queryParam: { 'depth': this.filterObj.depthCount } });
|
||||
},
|
||||
onClickResetLineage: function() {
|
||||
this.LineageHelperRef.refresh();
|
||||
},
|
||||
onClickSaveSvg: function(e, a) {
|
||||
this.LineageHelperRef.exportLineage();
|
||||
},
|
||||
onClickZoomIn: function() {
|
||||
this.LineageHelperRef.zoomIn();
|
||||
},
|
||||
onClickZoomOut: function() {
|
||||
this.LineageHelperRef.zoomOut();
|
||||
},
|
||||
fetchGraphData: function(options) {
|
||||
var that = this,
|
||||
queryParam = options && options.queryParam || {};
|
||||
this.$('.fontLoader').show();
|
||||
this.$('svg>g').hide();
|
||||
this.toggleDisableState({
|
||||
"el": that.$(".graph-button-group button,select[data-id='selectDepth']")
|
||||
"el": that.$graphButtonsEl,
|
||||
disabled: true
|
||||
});
|
||||
this.collection.getLineage(this.guid, {
|
||||
queryParam: queryParam,
|
||||
|
|
@ -232,24 +235,11 @@ define(['require',
|
|||
if (that.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
if (data.relations.length) {
|
||||
that.lineageData = $.extend(true, {}, data);
|
||||
that.generateData(that.lineageData).then(function(graphObj) {
|
||||
that.createGraph();
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl
|
||||
});
|
||||
});
|
||||
that.renderLineageTypeSearch().then(function() {
|
||||
that.ui.searchToggler.prop("disabled", false);
|
||||
});
|
||||
} else {
|
||||
that.noLineage();
|
||||
that.hideCheckForProcess();
|
||||
}
|
||||
|
||||
that.createGraph(data);
|
||||
that.renderLineageTypeSearch(data);
|
||||
},
|
||||
cust_error: function(model, response) {
|
||||
that.lineageData = [];
|
||||
that.noLineage();
|
||||
},
|
||||
complete: function() {
|
||||
|
|
@ -258,6 +248,80 @@ define(['require',
|
|||
}
|
||||
})
|
||||
},
|
||||
createGraph: function(data) {
|
||||
// if (_.isEmpty(this.g._nodes)) {
|
||||
// this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>');
|
||||
// return;
|
||||
// }
|
||||
var that = this;
|
||||
$('.resizeGraph').css("height", this.$('.svg').height() + "px");
|
||||
|
||||
this.LineageHelperRef = new LineageHelper.default({
|
||||
entityDefCollection: this.entityDefCollection.fullCollection.toJSON(),
|
||||
data: data,
|
||||
el: this.$('.svg')[0],
|
||||
legendsEl: this.$('.legends')[0],
|
||||
getFilterObj: function() {
|
||||
return {
|
||||
isProcessHideCheck: that.filterObj.isProcessHideCheck,
|
||||
isDeletedEntityHideCheck: that.filterObj.isDeletedEntityHideCheck
|
||||
}
|
||||
},
|
||||
isShowHoverPath: function() { return that.ui.showOnlyHoverPath.prop('checked') },
|
||||
isShowTooltip: function() { return that.ui.showTooltip.prop('checked') },
|
||||
onPathClick: function(d) {
|
||||
console.log("Path Clicked");
|
||||
if (d.pathRelationObj) {
|
||||
var relationshipId = d.pathRelationObj.relationshipId;
|
||||
require(['views/graph/PropagationPropertyModal'], function(PropagationPropertyModal) {
|
||||
var view = new PropagationPropertyModal({
|
||||
edgeInfo: d.pathRelationObj,
|
||||
relationshipId: relationshipId,
|
||||
lineageData: data,
|
||||
apiGuid: that.apiGuid,
|
||||
detailPageFetchCollection: that.fetchCollection
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
onNodeClick: function(d) {
|
||||
that.onClickNodeToggler();
|
||||
that.updateRelationshipDetails({ guid: d.clickedData });
|
||||
},
|
||||
onLabelClick: function(d) {
|
||||
var guid = d.clickedData;
|
||||
if (that.guid == guid) {
|
||||
Utils.notifyInfo({
|
||||
html: true,
|
||||
content: "You are already on " + "<b>" + that.entityName + "</b> detail page."
|
||||
});
|
||||
} else {
|
||||
Utils.setUrl({
|
||||
url: '#!/detailPage/' + guid + '?tabActive=lineage',
|
||||
mergeBrowserUrl: false,
|
||||
trigger: true
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeRender: function() {
|
||||
that.$('.fontLoader').show();
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl,
|
||||
disabled: true
|
||||
});
|
||||
},
|
||||
afterRender: function() {
|
||||
// Remove Loader
|
||||
that.$('.fontLoader').hide();
|
||||
if (data.relations.length) {
|
||||
that.toggleDisableState({
|
||||
"el": that.$graphButtonsEl,
|
||||
disabled: false
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
noLineage: function() {
|
||||
this.$('.fontLoader').hide();
|
||||
this.$('.depth-container').hide();
|
||||
|
|
@ -269,513 +333,14 @@ define(['require',
|
|||
hideCheckForProcess: function() {
|
||||
this.$('.hideProcessContainer').hide();
|
||||
},
|
||||
isProcess: function(node) {
|
||||
var typeName = node.typeName,
|
||||
superTypes = node.superTypes,
|
||||
entityDef = node.entityDef;
|
||||
if (typeName == "Process") {
|
||||
return true;
|
||||
}
|
||||
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)
|
||||
};
|
||||
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;
|
||||
}
|
||||
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;
|
||||
},
|
||||
generateData: function(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var that = this,
|
||||
relations = options && options.relations || {},
|
||||
guidEntityMap = options && options.guidEntityMap || {},
|
||||
isHideFilterOn = this.filterObj.isProcessHideCheck || this.filterObj.isDeletedEntityHideCheck,
|
||||
newHashMap = {},
|
||||
styleObj = {
|
||||
fill: 'none',
|
||||
stroke: '#ffb203',
|
||||
width: 3
|
||||
},
|
||||
makeNodeData = function(relationObj) {
|
||||
if (relationObj) {
|
||||
if (relationObj.updatedValues) {
|
||||
return relationObj;
|
||||
}
|
||||
var obj = _.extend(relationObj, {
|
||||
shape: "img",
|
||||
updatedValues: true,
|
||||
label: relationObj.displayText.trunc(18),
|
||||
toolTipLabel: relationObj.displayText,
|
||||
id: relationObj.guid,
|
||||
isLineage: true,
|
||||
isIncomplete: relationObj.isIncomplete,
|
||||
entityDef: that.getEntityDef(relationObj.typeName)
|
||||
});
|
||||
obj["serviceType"] = that.getServiceType({ typeName: relationObj.typeName, entityDef: obj.entityDef });
|
||||
obj["superTypes"] = that.getNestedSuperTypes({ entityDef: obj.entityDef });
|
||||
obj['isProcess'] = that.isProcess(obj);
|
||||
obj['isDeleted'] = that.isDeleted(obj);
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
crateLineageRelationshipHashMap = function(data) {
|
||||
var that = this,
|
||||
relations = data && data.relations,
|
||||
newHashMap = {};
|
||||
_.each(relations, function(obj) {
|
||||
if (newHashMap[obj.fromEntityId]) {
|
||||
newHashMap[obj.fromEntityId].push(obj.toEntityId);
|
||||
} else {
|
||||
newHashMap[obj.fromEntityId] = [obj.toEntityId];
|
||||
}
|
||||
});
|
||||
return newHashMap;
|
||||
},
|
||||
getStyleObjStr = function(styleObj) {
|
||||
return 'fill:' + styleObj.fill + ';stroke:' + styleObj.stroke + ';stroke-width:' + styleObj.width;
|
||||
},
|
||||
getNewToNodeRelationship = function(toNodeGuid) {
|
||||
if (toNodeGuid && relationshipMap[toNodeGuid]) {
|
||||
var newRelationship = [];
|
||||
_.each(relationshipMap[toNodeGuid], function(guid) {
|
||||
var nodeToBeUpdated = that.isNodeToBeUpdated(makeNodeData(guidEntityMap[guid]));
|
||||
if (nodeToBeUpdated.update) {
|
||||
var newRelation = getNewToNodeRelationship(guid);
|
||||
if (newRelation) {
|
||||
newRelationship = newRelationship.concat(newRelation);
|
||||
}
|
||||
} else {
|
||||
newRelationship.push(guid);
|
||||
}
|
||||
});
|
||||
return newRelationship;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
getToNodeRelation = function(toNodes, fromNodeToBeUpdated) {
|
||||
var toNodeRelationship = [];
|
||||
_.each(toNodes, function(toNodeGuid) {
|
||||
var toNodeToBeUpdated = that.isNodeToBeUpdated(makeNodeData(guidEntityMap[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;
|
||||
},
|
||||
setNode = function(guid) {
|
||||
if (!that.g._nodes[guid]) {
|
||||
var nodeData = makeNodeData(guidEntityMap[guid]);
|
||||
that.g.setNode(guid, nodeData);
|
||||
return nodeData;
|
||||
} else {
|
||||
return that.g._nodes[guid];
|
||||
}
|
||||
},
|
||||
setEdge = function(fromNodeGuid, toNodeGuid) {
|
||||
that.g.setEdge(fromNodeGuid, toNodeGuid, {
|
||||
"arrowhead": 'arrowPoint',
|
||||
"curve": LineageUtils.BezierCurve,
|
||||
"style": getStyleObjStr(styleObj),
|
||||
"styleObj": styleObj
|
||||
});
|
||||
},
|
||||
setGraphData = function(fromEntityId, toEntityId) {
|
||||
setNode(fromEntityId);
|
||||
setNode(toEntityId);
|
||||
setEdge(fromEntityId, toEntityId);
|
||||
},
|
||||
pendingFromRelationship = {};
|
||||
if (isHideFilterOn) {
|
||||
var relationshipMap = crateLineageRelationshipHashMap(options)
|
||||
_.each(relationshipMap, function(toNodes, fromNodeGuid) {
|
||||
var fromNodeToBeUpdated = that.isNodeToBeUpdated(makeNodeData(guidEntityMap[fromNodeGuid])),
|
||||
toNodeList = getToNodeRelation(toNodes, fromNodeToBeUpdated);
|
||||
if (fromNodeToBeUpdated.update) {
|
||||
if (pendingFromRelationship[fromNodeGuid]) {
|
||||
pendingFromRelationship[fromNodeGuid] = pendingFromRelationship[fromNodeGuid].concat(toNodeList);
|
||||
} else {
|
||||
pendingFromRelationship[fromNodeGuid] = toNodeList;
|
||||
}
|
||||
} else {
|
||||
_.each(toNodeList, function(toNodeGuid) {
|
||||
setGraphData(fromNodeGuid, toNodeGuid);
|
||||
});
|
||||
}
|
||||
})
|
||||
} else {
|
||||
_.each(relations, function(obj) {
|
||||
setGraphData(obj.fromEntityId, obj.toEntityId);
|
||||
});
|
||||
}
|
||||
if (this.g._nodes[this.guid]) {
|
||||
if (this.g._nodes[this.guid]) {
|
||||
this.g._nodes[this.guid]['isLineage'] = false;
|
||||
}
|
||||
this.findImpactNodeAndUpdateData({ "guid": this.guid, "getStyleObjStr": getStyleObjStr });
|
||||
}
|
||||
resolve(this.g);
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
findImpactNodeAndUpdateData: function(options) {
|
||||
var that = this,
|
||||
guid = options.guid,
|
||||
getStyleObjStr = options.getStyleObjStr,
|
||||
traversedMap = {},
|
||||
styleObj = {
|
||||
fill: 'none',
|
||||
stroke: '#fb4200',
|
||||
width: 3
|
||||
},
|
||||
traversed = function(toNodeList, fromNodeGuid) {
|
||||
if (!_.isEmpty(toNodeList)) {
|
||||
if (!traversedMap[fromNodeGuid]) {
|
||||
traversedMap[fromNodeGuid] = true;
|
||||
_.each(toNodeList, function(val, toNodeGuid) {
|
||||
if (that.g._nodes[toNodeGuid]) {
|
||||
that.g._nodes[toNodeGuid]['isLineage'] = false;
|
||||
}
|
||||
that.g.setEdge(fromNodeGuid, toNodeGuid, {
|
||||
"arrowhead": 'arrowPoint',
|
||||
"curve": LineageUtils.BezierCurve,
|
||||
"style": getStyleObjStr(styleObj),
|
||||
'styleObj': styleObj
|
||||
});
|
||||
traversed(that.g._sucs[toNodeGuid], toNodeGuid);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
traversed(this.g._sucs[guid], guid)
|
||||
},
|
||||
zoomed: function(that) {
|
||||
this.$('svg').find('>g').attr("transform",
|
||||
"translate(" + this.zoom.translate() + ")" +
|
||||
"scale(" + this.zoom.scale() + ")"
|
||||
);
|
||||
if (platform.name === "IE") {
|
||||
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() {
|
||||
if (_.isEmpty(this.g._nodes)) {
|
||||
this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relations to display</text>');
|
||||
return;
|
||||
}
|
||||
var that = this,
|
||||
width = this.$('svg').width(),
|
||||
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
|
||||
if (node) {
|
||||
node.rx = node.ry = 5;
|
||||
}
|
||||
});
|
||||
// Create the renderer
|
||||
var render = new dagreD3.render();
|
||||
// Add our custom arrow (a hollow-point)
|
||||
render.arrows().arrowPoint = function(parent, id, edge, type) {
|
||||
return LineageUtils.arrowPointRender(parent, id, edge, type, { guid: that.guid, dagreD3: dagreD3 });
|
||||
};
|
||||
// Render custom img inside shape
|
||||
render.shapes().img = function(parent, bbox, node) {
|
||||
return LineageUtils.imgShapeRender(parent, bbox, node, { guid: that.guid, dagreD3: dagreD3, imageObject: imageObject, $defs: that.svg.select('defs') });
|
||||
};
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
if (this.$("svg").find('.output').length) {
|
||||
this.$("svg").find('.output').parent('g').remove();
|
||||
}
|
||||
var svg = this.svg = d3.select(this.$("svg")[0])
|
||||
.attr("viewBox", "0 0 " + width + " " + height)
|
||||
.attr("enable-background", "new 0 0 " + width + " " + height),
|
||||
svgGroup = svg.append("g");
|
||||
// Append defs
|
||||
svg.append("defs");
|
||||
var zoom = this.zoom = d3.behavior.zoom()
|
||||
.center([width / 2, height / 2])
|
||||
.scaleExtent([0.01, 50])
|
||||
.on("zoom", that.zoomed.bind(this));
|
||||
|
||||
function zoomClick() {
|
||||
var clicked = d3.event.target,
|
||||
direction = 1,
|
||||
factor = 0.5,
|
||||
target_zoom = 1,
|
||||
center = [width / 2, height / 2],
|
||||
translate = zoom.translate(),
|
||||
translate0 = [],
|
||||
l = [],
|
||||
view = { x: translate[0], y: translate[1], k: zoom.scale() };
|
||||
|
||||
d3.event.preventDefault();
|
||||
direction = (this.id === 'zoom_in') ? 1 : -1;
|
||||
target_zoom = zoom.scale() * (1 + factor * direction);
|
||||
|
||||
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];
|
||||
|
||||
view.x += center[0] - l[0];
|
||||
view.y += center[1] - l[1];
|
||||
|
||||
that.interpolateZoom([view.x, view.y], view.k, that, zoom);
|
||||
}
|
||||
d3.selectAll(this.$('.lineageZoomButton')).on('click', zoomClick);
|
||||
var tooltip = d3Tip()
|
||||
.attr('class', 'd3-tip')
|
||||
.offset([10, 0])
|
||||
.html(function(d) {
|
||||
var value = that.g.node(d);
|
||||
var htmlStr = "";
|
||||
if (value.id !== that.guid) {
|
||||
htmlStr = "<h5 style='text-align: center;'>" + (value.isLineage ? "Lineage" : "Impact") + "</h5>";
|
||||
}
|
||||
htmlStr += "<h5 class='text-center'><span style='color:#359f89'>" + value.toolTipLabel + "</span></h5> ";
|
||||
if (value.typeName) {
|
||||
htmlStr += "<h5 class='text-center'><span>(" + value.typeName + ")</span></h5> ";
|
||||
}
|
||||
if (value.queryText) {
|
||||
htmlStr += "<h5>Query: <span style='color:#359f89'>" + value.queryText + "</span></h5> ";
|
||||
}
|
||||
return "<div class='tip-inner-scroll'>" + htmlStr + "</div>";
|
||||
});
|
||||
|
||||
svg.call(zoom)
|
||||
.call(tooltip);
|
||||
if (platform.name !== "IE") {
|
||||
this.$('.fontLoader').hide();
|
||||
}
|
||||
render(svgGroup, this.g);
|
||||
svg.on("dblclick.zoom", null)
|
||||
// .on("wheel.zoom", null);
|
||||
//change text postion
|
||||
svgGroup.selectAll("g.nodes g.label")
|
||||
.attr("transform", "translate(2,-35)")
|
||||
.on('mouseenter', function(d) {
|
||||
d3.select(this).classed("highlight", true);
|
||||
})
|
||||
.on('mouseleave', function(d) {
|
||||
d3.select(this).classed("highlight", false);
|
||||
})
|
||||
.on('click', function(d) {
|
||||
d3.event.preventDefault();
|
||||
tooltip.hide(d);
|
||||
if (that.guid == d) {
|
||||
Utils.notifyInfo({
|
||||
html: true,
|
||||
content: "You are already on " + "<b>" + that.entityName + "</b> detail page."
|
||||
});
|
||||
} else {
|
||||
Utils.setUrl({
|
||||
url: '#!/detailPage/' + d + '?tabActive=lineage',
|
||||
mergeBrowserUrl: false,
|
||||
trigger: true
|
||||
});
|
||||
}
|
||||
});
|
||||
svgGroup.selectAll("g.nodes g.node")
|
||||
.on('mouseenter', function(d) {
|
||||
that.activeNode = true;
|
||||
var matrix = this.getScreenCTM()
|
||||
.translate(+this.getAttribute("cx"), +this.getAttribute("cy"));
|
||||
that.$('svg').find('.node').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
// Fix
|
||||
var width = $('body').width();
|
||||
var currentELWidth = $(this).offset();
|
||||
var direction = 'e';
|
||||
if (((width - currentELWidth.left) < 330)) {
|
||||
direction = (((width - currentELWidth.left) < 330) && ((currentELWidth.top) < 400)) ? 'sw' : 'w';
|
||||
if (((width - currentELWidth.left) < 330) && ((currentELWidth.top) > 600)) {
|
||||
direction = 'nw';
|
||||
}
|
||||
} else if (((currentELWidth.top) > 600)) {
|
||||
direction = (((width - currentELWidth.left) < 330) && ((currentELWidth.top) > 600)) ? 'nw' : 'n';
|
||||
if ((currentELWidth.left) < 50) {
|
||||
direction = 'ne'
|
||||
}
|
||||
} else if ((currentELWidth.top) < 400) {
|
||||
direction = ((currentELWidth.left) < 50) ? 'se' : 's';
|
||||
}
|
||||
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('mouseleave', function(d) {
|
||||
that.activeNode = false;
|
||||
var nodeEL = this;
|
||||
setTimeout(function(argument) {
|
||||
if (!(that.activeTip || that.activeNode)) {
|
||||
$(nodeEL).removeClass('active');
|
||||
if (that.ui.showTooltip.prop('checked')) {
|
||||
tooltip.hide(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
|
||||
d3.event.preventDefault();
|
||||
tooltip.hide(d);
|
||||
that.onClickNodeToggler({ obj: d });
|
||||
$(el).find('circle').addClass('node-detail-highlight');
|
||||
that.updateRelationshipDetails({ guid: d });
|
||||
});
|
||||
|
||||
svgGroup.selectAll("g.edgePath path.path").on('click', function(d) {
|
||||
var data = { obj: _.find(that.lineageData.relations, { "fromEntityId": d.v, "toEntityId": d.w }) };
|
||||
if (data.obj) {
|
||||
var 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;
|
||||
});
|
||||
$('body').on('mouseleave', '.d3-tip', function(el) {
|
||||
that.activeTip = false;
|
||||
that.$('svg').find('.node').removeClass('active');
|
||||
tooltip.hide();
|
||||
});
|
||||
|
||||
// Center the graph
|
||||
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);
|
||||
if (platform.name === "IE") {
|
||||
LineageUtils.refreshGraphForIE({
|
||||
edgeEl: this.$('svg .edgePath')
|
||||
});
|
||||
}
|
||||
LineageUtils.DragNode({
|
||||
svg: this.svg,
|
||||
g: this.g,
|
||||
guid: this.guid,
|
||||
edgeEl: this.$('svg .edgePath')
|
||||
}).init();
|
||||
},
|
||||
renderLineageTypeSearch: function() {
|
||||
renderLineageTypeSearch: function(data) {
|
||||
var that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var data = [],
|
||||
typeStr = '<option></option>';
|
||||
if (!_.isEmpty(that.lineageData)) {
|
||||
_.each(that.lineageData.guidEntityMap, function(obj, index) {
|
||||
var nodeData = that.g._nodes[obj.guid];
|
||||
var typeStr = '<option></option>';
|
||||
if (!_.isEmpty(data)) {
|
||||
_.each(data.guidEntityMap, function(obj, index) {
|
||||
var nodeData = that.LineageHelperRef.getNode(obj.guid);
|
||||
if ((that.filterObj.isProcessHideCheck || that.filterObj.isDeletedEntityHideCheck) && nodeData && (nodeData.isProcess || nodeData.isDeleted)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -799,42 +364,9 @@ define(['require',
|
|||
}).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);
|
||||
}
|
||||
}).init();
|
||||
that.svg.selectAll('.nodes g.label').attr('stroke', function(c, d) {
|
||||
if (c == selectedNode) {
|
||||
return "#316132";
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
});
|
||||
that.LineageHelperRef.searchNode({ guid: selectedNode });
|
||||
});
|
||||
if (this.searchNodeObj.selectedNode) {
|
||||
this.ui.lineageTypeSearch.val(this.searchNodeObj.selectedNode);
|
||||
|
|
@ -844,8 +376,11 @@ define(['require',
|
|||
updateRelationshipDetails: function(options) {
|
||||
var that = this,
|
||||
guid = options.guid,
|
||||
initialData = that.g._nodes[guid],
|
||||
typeName = initialData.typeName || guid,
|
||||
initialData = that.LineageHelperRef.getNode(guid);
|
||||
if (initialData === undefined) {
|
||||
return;
|
||||
}
|
||||
var typeName = initialData.typeName || guid,
|
||||
attributeDefs = initialData && initialData.entityDef ? initialData.entityDef.attributeDefs : null;
|
||||
this.$("[data-id='typeName']").text(typeName);
|
||||
this.entityModel = new VEntity({});
|
||||
|
|
@ -876,46 +411,6 @@ define(['require',
|
|||
"attributeDefs": attributeDefs,
|
||||
"sortBy": false
|
||||
}));
|
||||
},
|
||||
onClickSaveSvg: function(e, a) {
|
||||
var that = this,
|
||||
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.
|
||||
}
|
||||
this.toggleLoader(loaderTargetDiv);
|
||||
Utils.notifyInfo({
|
||||
content: "Lineage will be downloaded in a moment."
|
||||
});
|
||||
var entityAttributes = that.entity && that.entity.attributes;
|
||||
LineageUtils.SaveSvg(e, {
|
||||
svg: that.$('svg')[0],
|
||||
svgWidth: that.$('svg').width(),
|
||||
svgHeight: that.$('svg').height(),
|
||||
toggleLoader: function() {
|
||||
that.toggleLoader(loaderTargetDiv);
|
||||
},
|
||||
downloadFileName: ((entityAttributes && (entityAttributes.qualifiedName || entityAttributes.name) || "lineage_export") + ".png")
|
||||
})
|
||||
},
|
||||
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"));
|
||||
}
|
||||
}
|
||||
});
|
||||
return LineageLayoutView;
|
||||
|
|
|
|||
|
|
@ -1,524 +0,0 @@
|
|||
/**
|
||||
* 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'], function(require, Utils) {
|
||||
'use strict';
|
||||
var LineageUtils = {};
|
||||
LineageUtils.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 + ')');
|
||||
}
|
||||
}
|
||||
});
|
||||
LineageUtils.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
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
LineageUtils.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);
|
||||
});
|
||||
}
|
||||
LineageUtils.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);
|
||||
});
|
||||
}
|
||||
LineageUtils.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] });
|
||||
if (platform.name === "IE") {
|
||||
LineageUtils.refreshGraphForIE({ "edgeEl": edgePathEl })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LineageUtils.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;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
LineageUtils.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;
|
||||
}
|
||||
LineageUtils.imgShapeRender = function(parent, bbox, node, viewOptions) {
|
||||
var LineageUtilsRef = this,
|
||||
imageIconPath = Utils.getEntityIconPath({ entityData: node }),
|
||||
imgName = imageIconPath.split("/").pop(),
|
||||
viewGuid = viewOptions.guid,
|
||||
dagreD3 = viewOptions.dagreD3,
|
||||
imageObject = viewOptions.imageObject,
|
||||
$defs = viewOptions.$defs;
|
||||
if (node.isDeleted) {
|
||||
imgName = "deleted_" + imgName;
|
||||
}
|
||||
if (node.id == viewGuid) {
|
||||
var currentNode = true
|
||||
}
|
||||
var shapeSvg = parent.append('circle')
|
||||
.attr('fill', 'url(#img_' + imgName + ')')
|
||||
.attr('r', '24px')
|
||||
.attr('data-stroke', node.id)
|
||||
.attr('stroke-width', "2px")
|
||||
.attr("class", "nodeImage " + (currentNode ? "currentNode" : (node.isProcess ? "process" : "node")));
|
||||
if (currentNode) {
|
||||
shapeSvg.attr("stroke", "#fb4200")
|
||||
}
|
||||
|
||||
if ($defs.select('pattern[id="img_' + imgName + '"]').empty()) {
|
||||
var $pattern = $defs.append("pattern")
|
||||
.attr("x", "0%")
|
||||
.attr("y", "0%")
|
||||
.attr("patternUnits", "objectBoundingBox")
|
||||
.attr("id", "img_" + imgName)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.append('image')
|
||||
.attr("href", function(d) {
|
||||
var that = this;
|
||||
if (node) {
|
||||
var getImageData = function(options) {
|
||||
var imagePath = options.imagePath,
|
||||
ajaxOptions = {
|
||||
"url": imagePath,
|
||||
"method": "get",
|
||||
"cache": true
|
||||
}
|
||||
|
||||
if (platform.name !== "IE") {
|
||||
ajaxOptions["mimeType"] = "text/plain; charset=x-user-defined";
|
||||
}
|
||||
shapeSvg.attr("data-iconpath", imagePath);
|
||||
$.ajax(ajaxOptions)
|
||||
.always(function(data, status, xhr) {
|
||||
if (data.status == 404) {
|
||||
getImageData({
|
||||
"imagePath": Utils.getEntityIconPath({ entityData: node, errorUrl: imagePath })
|
||||
});
|
||||
} else if (data) {
|
||||
if (platform.name !== "IE") {
|
||||
imageObject[imageIconPath] = 'data:image/png;base64,' + LineageUtilsRef.base64Encode({ "data": data });
|
||||
} else {
|
||||
imageObject[imageIconPath] = imagePath;
|
||||
}
|
||||
d3.select(that).attr("xlink:href", imageObject[imageIconPath]);
|
||||
if (imageIconPath !== shapeSvg.attr("data-iconpath")) {
|
||||
shapeSvg.attr("data-iconpathorigin", imageIconPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
getImageData({
|
||||
"imagePath": imageIconPath
|
||||
});
|
||||
}
|
||||
})
|
||||
.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);
|
||||
};
|
||||
return shapeSvg;
|
||||
}
|
||||
LineageUtils.arrowPointRender = function(parent, id, edge, type, viewOptions) {
|
||||
var node = parent.node(),
|
||||
parentNode = node ? node.parentNode : parent,
|
||||
dagreD3 = viewOptions.dagreD3;
|
||||
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")
|
||||
.attr("refX", 8)
|
||||
.attr("refY", 5)
|
||||
.attr("markerUnits", "strokeWidth")
|
||||
.attr("markerWidth", 4)
|
||||
.attr("markerHeight", 4)
|
||||
.attr("orient", "auto");
|
||||
|
||||
var path = marker.append("path")
|
||||
.attr("d", "M 0 0 L 10 5 L 0 10 z")
|
||||
.style("fill", edge.styleObj.stroke);
|
||||
dagreD3.util.applyStyle(path, edge[type + "Style"]);
|
||||
}
|
||||
LineageUtils.BezierCurve = function(context) {
|
||||
return {
|
||||
lineStart: function() {
|
||||
this.data = [];
|
||||
},
|
||||
point: function(x, y) {
|
||||
this.data.push([x, y]);
|
||||
},
|
||||
lineEnd: function() {
|
||||
var x0 = this.data[0][0],
|
||||
y0 = this.data[0][1],
|
||||
cp1x = this.data[1][0],
|
||||
cp1y = this.data[1][1],
|
||||
cp2Obj = this.data[this.data.length - 2],
|
||||
cp2x = cp2Obj[0],
|
||||
cp2y = cp2Obj[1],
|
||||
axisObj = this.data[this.data.length - 1],
|
||||
x1 = axisObj[0],
|
||||
y1 = axisObj[1];
|
||||
context.moveTo(x0, y0);
|
||||
context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x1, y1);
|
||||
}
|
||||
}
|
||||
}
|
||||
LineageUtils.SaveSvg = function(e, viewOptions) {
|
||||
var that = this,
|
||||
svg = viewOptions.svg,
|
||||
svgWidth = viewOptions.svgWidth,
|
||||
svgHeight = viewOptions.svgHeight,
|
||||
downloadFileName = viewOptions.downloadFileName,
|
||||
toggleLoader = viewOptions.toggleLoader,
|
||||
svgClone = svg.cloneNode(true),
|
||||
scaleFactor = 1;
|
||||
setTimeout(function() {
|
||||
if (platform.name === "Firefox") {
|
||||
svgClone.setAttribute('width', svgWidth);
|
||||
svgClone.setAttribute('height', svgHeight);
|
||||
}
|
||||
$('.hidden-svg').html(svgClone);
|
||||
$(svgClone).find('>g').attr("transform", "scale(" + scaleFactor + ")");
|
||||
$(svgClone).find("foreignObject").remove();
|
||||
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");
|
||||
a.download = downloadFileName;
|
||||
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!"
|
||||
});
|
||||
toggleLoader();
|
||||
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();
|
||||
toggleLoader();
|
||||
if (platform.name === 'Safari') {
|
||||
that.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!"
|
||||
});
|
||||
toggleLoader();
|
||||
}
|
||||
|
||||
};
|
||||
img.src = url;
|
||||
}, 0);
|
||||
}
|
||||
return LineageUtils;
|
||||
});
|
||||
|
|
@ -147,7 +147,7 @@ define(['require',
|
|||
|
||||
onRender: function() {},
|
||||
updateEdgeView: function(options) {
|
||||
var obj = options.obj,
|
||||
var obj = options,
|
||||
fromEntity = this.lineageData.guidEntityMap[obj.fromEntityId],
|
||||
toEntity = this.lineageData.guidEntityMap[obj.toEntityId];
|
||||
if (fromEntity && toEntity) {
|
||||
|
|
@ -183,9 +183,9 @@ define(['require',
|
|||
that.ui.propagationOptions.find('.both').show();
|
||||
} else {
|
||||
that.ui.propagationOptions.find('.both').hide();
|
||||
if (that.edgeInfo.obj.fromEntityId != relationshipObj.end1.guid && relationshipObj.propagateTags == "ONE_TO_TWO") {
|
||||
if (that.edgeInfo.fromEntityId != relationshipObj.end1.guid && relationshipObj.propagateTags == "ONE_TO_TWO") {
|
||||
isTwoToOne = true;
|
||||
} else if (that.edgeInfo.obj.fromEntityId == relationshipObj.end1.guid && relationshipObj.propagateTags == "TWO_TO_ONE") {
|
||||
} else if (that.edgeInfo.fromEntityId == relationshipObj.end1.guid && relationshipObj.propagateTags == "TWO_TO_ONE") {
|
||||
isTwoToOne = true;
|
||||
}
|
||||
if (isTwoToOne) {
|
||||
|
|
@ -241,7 +241,7 @@ define(['require',
|
|||
relationshipProp = {
|
||||
"propagateTags": that.getPropagationFlow({
|
||||
"relationshipData": _.extend({}, this.apiGuid[entityId].relationship, { 'propagateTags': PropagationValue }),
|
||||
"graphData": { from: { guid: this.edgeInfo.obj.fromEntityId } }
|
||||
"graphData": { from: { guid: this.edgeInfo.fromEntityId } }
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -16,24 +16,26 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
define(['require',
|
||||
'backbone',
|
||||
'hbs!tmpl/graph/RelationshipLayoutView_tmpl',
|
||||
'collection/VLineageList',
|
||||
'models/VEntity',
|
||||
'utils/Utils',
|
||||
'utils/CommonViewFunction',
|
||||
'd3-tip',
|
||||
'utils/Enums',
|
||||
'utils/UrlLinks',
|
||||
'platform'
|
||||
], function(require, Backbone, RelationshipLayoutViewtmpl, VLineageList, VEntity, Utils, CommonViewFunction, d3Tip, Enums, UrlLinks, platform) {
|
||||
'use strict';
|
||||
define([
|
||||
"require",
|
||||
"backbone",
|
||||
"hbs!tmpl/graph/RelationshipLayoutView_tmpl",
|
||||
"collection/VLineageList",
|
||||
"models/VEntity",
|
||||
"utils/Utils",
|
||||
"utils/CommonViewFunction",
|
||||
"d3",
|
||||
"d3-tip",
|
||||
"utils/Enums",
|
||||
"utils/UrlLinks",
|
||||
"platform"
|
||||
], function(require, Backbone, RelationshipLayoutViewtmpl, VLineageList, VEntity, Utils, CommonViewFunction, d3, d3Tip, Enums, UrlLinks, platform) {
|
||||
"use strict";
|
||||
|
||||
var RelationshipLayoutView = Backbone.Marionette.LayoutView.extend(
|
||||
/** @lends RelationshipLayoutView */
|
||||
{
|
||||
_viewName: 'RelationshipLayoutView',
|
||||
_viewName: "RelationshipLayoutView",
|
||||
|
||||
template: RelationshipLayoutViewtmpl,
|
||||
className: "resizeGraph",
|
||||
|
|
@ -61,15 +63,15 @@ define(['require',
|
|||
events["click " + this.ui.relationshipDetailClose] = function() {
|
||||
this.toggleInformationSlider({ close: true });
|
||||
};
|
||||
events["keyup " + this.ui.searchNode] = 'searchNode';
|
||||
events["click " + this.ui.boxClose] = 'toggleBoxPanel';
|
||||
events["keyup " + this.ui.searchNode] = "searchNode";
|
||||
events["click " + this.ui.boxClose] = "toggleBoxPanel";
|
||||
events["change " + this.ui.relationshipViewToggle] = function(e) {
|
||||
this.relationshipViewToggle(e.currentTarget.checked)
|
||||
this.relationshipViewToggle(e.currentTarget.checked);
|
||||
};
|
||||
events["click " + this.ui.noValueToggle] = function(e) {
|
||||
Utils.togglePropertyRelationshipTableEmptyValues({
|
||||
"inputType": this.ui.noValueToggle,
|
||||
"tableEl": this.ui.relationshipDetailValue
|
||||
inputType: this.ui.noValueToggle,
|
||||
tableEl: this.ui.relationshipDetailValue
|
||||
});
|
||||
};
|
||||
return events;
|
||||
|
|
@ -80,7 +82,7 @@ define(['require',
|
|||
* @constructs
|
||||
*/
|
||||
initialize: function(options) {
|
||||
_.extend(this, _.pick(options, 'entity', 'entityName', 'guid', 'actionCallBack', 'attributeDefs'));
|
||||
_.extend(this, _.pick(options, "entity", "entityName", "guid", "actionCallBack", "attributeDefs"));
|
||||
this.graphData = this.createData(this.entity);
|
||||
},
|
||||
createData: function(entity) {
|
||||
|
|
@ -91,14 +93,14 @@ define(['require',
|
|||
_.each(entity.relationshipAttributes, function(obj, key) {
|
||||
if (!_.isEmpty(obj)) {
|
||||
links.push({
|
||||
"source": nodes[that.entity.typeName] ||
|
||||
(nodes[that.entity.typeName] = _.extend({ "name": that.entity.typeName }, { value: entity })),
|
||||
"target": nodes[key] ||
|
||||
source: nodes[that.entity.typeName] ||
|
||||
(nodes[that.entity.typeName] = _.extend({ name: that.entity.typeName }, { value: entity })),
|
||||
target: nodes[key] ||
|
||||
(nodes[key] = _.extend({
|
||||
"name": key
|
||||
name: key
|
||||
}, { value: obj })),
|
||||
"value": obj
|
||||
})
|
||||
value: obj
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -106,7 +108,7 @@ define(['require',
|
|||
},
|
||||
onRender: function() {
|
||||
this.ui.zoomControl.hide();
|
||||
this.$el.addClass('auto-height');
|
||||
this.$el.addClass("auto-height");
|
||||
},
|
||||
onShow: function(argument) {
|
||||
if (this.graphData && _.isEmpty(this.graphData.links)) {
|
||||
|
|
@ -122,26 +124,26 @@ define(['require',
|
|||
//this.$('svg').html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relationship data found</text>');
|
||||
},
|
||||
toggleInformationSlider: function(options) {
|
||||
if (options.open && !this.$('.relationship-details').hasClass("open")) {
|
||||
this.$('.relationship-details').addClass('open');
|
||||
} else if (options.close && this.$('.relationship-details').hasClass("open")) {
|
||||
d3.selectAll('circle').attr("stroke", "none");
|
||||
this.$('.relationship-details').removeClass('open');
|
||||
if (options.open && !this.$(".relationship-details").hasClass("open")) {
|
||||
this.$(".relationship-details").addClass("open");
|
||||
} else if (options.close && this.$(".relationship-details").hasClass("open")) {
|
||||
d3.selectAll("circle").attr("stroke", "none");
|
||||
this.$(".relationship-details").removeClass("open");
|
||||
}
|
||||
},
|
||||
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');
|
||||
this.$el.find(".show-box-panel").removeClass("show-box-panel");
|
||||
if (el && el.addClass) {
|
||||
el.addClass('show-box-panel');
|
||||
el.addClass("show-box-panel");
|
||||
}
|
||||
this.$('circle.node-detail-highlight').removeClass("node-detail-highlight");
|
||||
this.$("circle.node-detail-highlight").removeClass("node-detail-highlight");
|
||||
},
|
||||
searchNode: function(e) {
|
||||
var $el = $(e.currentTarget);
|
||||
this.updateRelationshipDetails(_.extend({}, $el.data(), { searchString: $el.val() }))
|
||||
this.updateRelationshipDetails(_.extend({}, $el.data(), { searchString: $el.val() }));
|
||||
},
|
||||
updateRelationshipDetails: function(options) {
|
||||
var data = options.obj.value,
|
||||
|
|
@ -151,17 +153,17 @@ define(['require',
|
|||
getEntityTypelist = function(options) {
|
||||
var activeEntityColor = "#4a90e2",
|
||||
deletedEntityColor = "#BB5838",
|
||||
entityTypeHtml = '<pre>',
|
||||
entityTypeHtml = "<pre>",
|
||||
getdefault = function(obj) {
|
||||
var options = obj.options,
|
||||
status = (Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : ''),
|
||||
status = Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : "",
|
||||
guid = options.guid,
|
||||
entityColor = obj.color,
|
||||
name = obj.name,
|
||||
typeName = options.typeName;
|
||||
if (typeName === "AtlasGlossaryTerm") {
|
||||
return '<li class=' + status + '>' +
|
||||
'<a style="color:' + entityColor + '" href="#!/glossary/' + guid + '?guid=' + guid + '&gType=term&viewType=term">' + name + ' (' + typeName + ')</a>' +
|
||||
'<a style="color:' + entityColor + '" href="#!/glossary/' + guid + '?guid=' + guid + '&gType=term&viewType=term&fromView=entity">' + name + ' (' + typeName + ')</a>' +
|
||||
'</li>';
|
||||
} else {
|
||||
return "<li class=" + status + ">" +
|
||||
|
|
@ -171,7 +173,7 @@ define(['require',
|
|||
},
|
||||
getWithButton = function(obj) {
|
||||
var options = obj.options,
|
||||
status = (Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : ''),
|
||||
status = Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : "",
|
||||
guid = options.guid,
|
||||
entityColor = obj.color,
|
||||
name = obj.name,
|
||||
|
|
@ -182,7 +184,7 @@ define(['require',
|
|||
title = "Deleted";
|
||||
if (relationship) {
|
||||
icon = '<i class="fa fa-long-arrow-right"></i>';
|
||||
status = (Enums.entityStateReadOnly[options.relationshipStatus || options.status] ? "deleted-relation" : '');
|
||||
status = Enums.entityStateReadOnly[options.relationshipStatus || options.status] ? "deleted-relation" : "";
|
||||
title = "Relationship Deleted";
|
||||
}
|
||||
return "<li class=" + status + ">" +
|
||||
|
|
@ -195,33 +197,33 @@ define(['require',
|
|||
if (options.entityStatus == "ACTIVE") {
|
||||
if (options.relationshipStatus == "ACTIVE") {
|
||||
entityTypeHtml = getdefault({
|
||||
"color": activeEntityColor,
|
||||
"options": options,
|
||||
"name": name
|
||||
color: activeEntityColor,
|
||||
options: options,
|
||||
name: name
|
||||
});
|
||||
} else if (options.relationshipStatus == "DELETED") {
|
||||
entityTypeHtml = getWithButton({
|
||||
"color": activeEntityColor,
|
||||
"options": options,
|
||||
"name": name,
|
||||
"relationship": true
|
||||
})
|
||||
color: activeEntityColor,
|
||||
options: options,
|
||||
name: name,
|
||||
relationship: true
|
||||
});
|
||||
}
|
||||
} else if (options.entityStatus == "DELETED") {
|
||||
entityTypeHtml = getWithButton({
|
||||
"color": deletedEntityColor,
|
||||
"options": options,
|
||||
"name": name,
|
||||
"entity": true
|
||||
})
|
||||
color: deletedEntityColor,
|
||||
options: options,
|
||||
name: name,
|
||||
entity: true
|
||||
});
|
||||
} else {
|
||||
entityTypeHtml = getdefault({
|
||||
"color": activeEntityColor,
|
||||
"options": options,
|
||||
"name": name
|
||||
color: activeEntityColor,
|
||||
options: options,
|
||||
name: name
|
||||
});
|
||||
}
|
||||
return entityTypeHtml + '</pre>';
|
||||
return entityTypeHtml + "</pre>";
|
||||
};
|
||||
this.ui.searchNode.hide();
|
||||
this.$("[data-id='typeName']").text(typeName);
|
||||
|
|
@ -229,7 +231,7 @@ define(['require',
|
|||
var name = options.entityName ? options.entityName : Utils.getName(options, "displayText");
|
||||
var entityTypeButton = getEntityTypelist(options);
|
||||
return entityTypeButton;
|
||||
}
|
||||
};
|
||||
if (_.isArray(data)) {
|
||||
if (data.length > 1) {
|
||||
this.ui.searchNode.show();
|
||||
|
|
@ -253,121 +255,248 @@ define(['require',
|
|||
this.$("[data-id='entityList']").html(listString);
|
||||
},
|
||||
createGraph: function(data) {
|
||||
var that = this,
|
||||
width = this.$('svg').width(),
|
||||
height = this.$('svg').height();
|
||||
//Ref - http://bl.ocks.org/fancellu/2c782394602a93921faff74e594d1bb1
|
||||
|
||||
var scale = 1.0,
|
||||
activeEntityColor = "#00b98b",
|
||||
var that = this,
|
||||
width = this.$("svg").width(),
|
||||
height = this.$("svg").height(),
|
||||
nodes = d3.values(data.nodes),
|
||||
links = data.links;
|
||||
|
||||
var activeEntityColor = "#00b98b",
|
||||
deletedEntityColor = "#BB5838",
|
||||
defaultEntityColor = "#e0e0e0",
|
||||
selectedNodeColor = "#4a90e2";
|
||||
|
||||
var force = d3.layout.force()
|
||||
.nodes(d3.values(data.nodes))
|
||||
.links(data.links)
|
||||
.size([width, height])
|
||||
.linkDistance(200)
|
||||
.gravity(0.5)
|
||||
.friction(0.1)
|
||||
.charge(function(d) {
|
||||
var charge = -2000;
|
||||
if (d.index === 0) charge = 100
|
||||
return charge;
|
||||
})
|
||||
.on("tick", tick)
|
||||
.start();
|
||||
|
||||
var zoom = d3.behavior.zoom()
|
||||
.scale(scale)
|
||||
.scaleExtent([1, 5])
|
||||
.on("zoom", zoomed);
|
||||
|
||||
function zoomed() {
|
||||
container.attr("transform",
|
||||
"translate(" + zoom.translate() + ")" +
|
||||
"scale(" + zoom.scale() + ")"
|
||||
);
|
||||
}
|
||||
|
||||
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));
|
||||
zoomed();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function zoomClick() {
|
||||
var clicked = d3.event.target,
|
||||
direction = 1,
|
||||
factor = 0.5,
|
||||
target_zoom = 1,
|
||||
center = [width / 2, height / 2],
|
||||
extent = zoom.scaleExtent(),
|
||||
translate = zoom.translate(),
|
||||
translate0 = [],
|
||||
l = [],
|
||||
view = { x: translate[0], y: translate[1], k: zoom.scale() };
|
||||
|
||||
d3.event.preventDefault();
|
||||
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];
|
||||
|
||||
view.x += center[0] - l[0];
|
||||
view.y += center[1] - l[1];
|
||||
|
||||
interpolateZoom([view.x, view.y], view.k);
|
||||
}
|
||||
|
||||
|
||||
|
||||
d3.selectAll(this.$('.lineageZoomButton')).on('click', zoomClick);
|
||||
|
||||
var svg = d3.select(this.$("svg")[0])
|
||||
var svg = d3
|
||||
.select(this.$("svg")[0])
|
||||
.attr("viewBox", "0 0 " + width + " " + height)
|
||||
.attr("enable-background", "new 0 0 " + width + " " + height)
|
||||
.call(zoom)
|
||||
.on("dblclick.zoom", null),
|
||||
drag = force.drag()
|
||||
.on("dragstart", dragstart);
|
||||
.attr("enable-background", "new 0 0 " + width + " " + height),
|
||||
node,
|
||||
path;
|
||||
|
||||
var container = svg.append("g")
|
||||
var container = svg
|
||||
.append("g")
|
||||
.attr("id", "container")
|
||||
.attr("transform", "translate(0,0)scale(1,1)");
|
||||
|
||||
|
||||
// build the arrow.
|
||||
container.append("svg:defs").selectAll("marker")
|
||||
.data(["deletedLink", "activeLink"]) // Different link/path types can be defined here
|
||||
.enter().append("svg:marker") // This section adds in the arrows
|
||||
.attr("id", String)
|
||||
.attr("viewBox", "0 -5 10 10")
|
||||
.attr("refX", 10)
|
||||
.attr("refY", -0.5)
|
||||
.attr("markerWidth", 6)
|
||||
.attr("markerHeight", 6)
|
||||
.attr("orient", "auto")
|
||||
.append("svg:path")
|
||||
.attr("d", "M0,-5L10,0L0,5")
|
||||
.attr("fill", function(d) {
|
||||
return d == "deletedLink" ? deletedEntityColor : activeEntityColor;
|
||||
var zoom = d3
|
||||
.zoom()
|
||||
.scaleExtent([0.1, 4])
|
||||
.on("zoom", function() {
|
||||
container.attr("transform", d3.event.transform);
|
||||
});
|
||||
|
||||
svg.call(zoom).on("dblclick.zoom", null);
|
||||
|
||||
container
|
||||
.append("svg:defs")
|
||||
.selectAll("marker")
|
||||
.data(["deletedLink", "activeLink"]) // Different link/path types can be defined here
|
||||
.enter()
|
||||
.append("svg:marker") // This section adds in the arrows
|
||||
.attr("id", String)
|
||||
.attr("viewBox", "-0 -5 10 10")
|
||||
.attr("refX", 10)
|
||||
.attr("refY", -0.5)
|
||||
.attr("orient", "auto")
|
||||
.attr("markerWidth", 6)
|
||||
.attr("markerHeight", 6)
|
||||
.append("svg:path")
|
||||
.attr("d", "M 0,-5 L 10 ,0 L 0,5")
|
||||
.attr("fill", function(d) {
|
||||
return d == "deletedLink" ? deletedEntityColor : activeEntityColor;
|
||||
})
|
||||
.style("stroke", "none");
|
||||
|
||||
var forceLink = d3
|
||||
.forceLink()
|
||||
.id(function(d) {
|
||||
return d.id;
|
||||
})
|
||||
.distance(function(d) {
|
||||
return 100;
|
||||
})
|
||||
.strength(1);
|
||||
|
||||
var simulation = d3
|
||||
.forceSimulation()
|
||||
.force("link", forceLink)
|
||||
.force("charge", d3.forceManyBody())
|
||||
.force("center", d3.forceCenter(width / 2, height / 2));
|
||||
|
||||
update();
|
||||
|
||||
function update() {
|
||||
path = container
|
||||
.append("svg:g")
|
||||
.selectAll("path")
|
||||
.data(links)
|
||||
.enter()
|
||||
.append("svg:path")
|
||||
.attr("class", "relatioship-link")
|
||||
.attr("stroke", function(d) {
|
||||
return getPathColor({ data: d, type: "path" });
|
||||
})
|
||||
.attr("marker-end", function(d) {
|
||||
return "url(#" + (isAllEntityRelationDeleted({ data: d }) ? "deletedLink" : "activeLink") + ")";
|
||||
});
|
||||
|
||||
node = container
|
||||
.selectAll(".node")
|
||||
.data(nodes)
|
||||
.enter()
|
||||
.append("g")
|
||||
.attr("class", "node")
|
||||
.on("mousedown", function() {
|
||||
console.log(d3.event);
|
||||
d3.event.preventDefault();
|
||||
})
|
||||
.on("click", function(d) {
|
||||
if (d3.event.defaultPrevented) return; // ignore drag
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
that.ui.boxClose.trigger("click");
|
||||
return;
|
||||
}
|
||||
that.toggleBoxPanel({ el: that.$(".relationship-node-details") });
|
||||
that.ui.searchNode.data({ obj: d });
|
||||
$(this)
|
||||
.find("circle")
|
||||
.addClass("node-detail-highlight");
|
||||
that.updateRelationshipDetails({ obj: d });
|
||||
})
|
||||
.call(
|
||||
d3
|
||||
.drag()
|
||||
.on("start", dragstarted)
|
||||
.on("drag", dragged)
|
||||
);
|
||||
|
||||
var circleContainer = node.append("g");
|
||||
|
||||
circleContainer
|
||||
.append("circle")
|
||||
.attr("cx", 0)
|
||||
.attr("cy", 0)
|
||||
.attr("r", function(d) {
|
||||
d.radius = 25;
|
||||
return d.radius;
|
||||
})
|
||||
.attr("fill", function(d) {
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
if (isAllEntityRelationDeleted({ data: d, type: "node" })) {
|
||||
return deletedEntityColor;
|
||||
} else {
|
||||
return selectedNodeColor;
|
||||
}
|
||||
} else if (isAllEntityRelationDeleted({ data: d, type: "node" })) {
|
||||
return deletedEntityColor;
|
||||
} else {
|
||||
return activeEntityColor;
|
||||
}
|
||||
})
|
||||
.attr("typename", function(d) {
|
||||
return d.name;
|
||||
});
|
||||
|
||||
circleContainer
|
||||
.append("text")
|
||||
.attr("x", 0)
|
||||
.attr("y", 0)
|
||||
.attr("dy", 25 - 17)
|
||||
.attr("text-anchor", "middle")
|
||||
.style("font-family", "FontAwesome")
|
||||
.style("font-size", function(d) {
|
||||
return "25px";
|
||||
})
|
||||
.text(function(d) {
|
||||
var iconObj = Enums.graphIcon[d.name];
|
||||
if (iconObj && iconObj.textContent) {
|
||||
return iconObj.textContent;
|
||||
} else {
|
||||
if (d && _.isArray(d.value) && d.value.length > 1) {
|
||||
return "\uf0c5";
|
||||
} else {
|
||||
return "\uf016";
|
||||
}
|
||||
}
|
||||
})
|
||||
.attr("fill", function(d) {
|
||||
return "#fff";
|
||||
});
|
||||
|
||||
var countBox = circleContainer.append("g");
|
||||
|
||||
countBox
|
||||
.append("circle")
|
||||
.attr("cx", 18)
|
||||
.attr("cy", -20)
|
||||
.attr("r", function(d) {
|
||||
if (_.isArray(d.value) && d.value.length > 1) {
|
||||
return 10;
|
||||
}
|
||||
});
|
||||
|
||||
countBox
|
||||
.append("text")
|
||||
.attr("dx", 18)
|
||||
.attr("dy", -16)
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("fill", defaultEntityColor)
|
||||
.text(function(d) {
|
||||
if (_.isArray(d.value) && d.value.length > 1) {
|
||||
return d.value.length;
|
||||
}
|
||||
});
|
||||
|
||||
node.append("text")
|
||||
.attr("x", -15)
|
||||
.attr("y", "35")
|
||||
.text(function(d) {
|
||||
return d.name;
|
||||
});
|
||||
|
||||
simulation.nodes(nodes).on("tick", ticked);
|
||||
|
||||
simulation.force("link").links(links);
|
||||
}
|
||||
|
||||
function ticked() {
|
||||
path.attr("d", function(d) {
|
||||
var diffX = d.target.x - d.source.x,
|
||||
diffY = d.target.y - d.source.y,
|
||||
// Length of path from center of source node to center of target node
|
||||
pathLength = Math.sqrt(diffX * diffX + diffY * diffY),
|
||||
// x and y distances from center to outside edge of target node
|
||||
offsetX = (diffX * d.target.radius) / pathLength,
|
||||
offsetY = (diffY * d.target.radius) / pathLength;
|
||||
|
||||
return "M" + d.source.x + "," + d.source.y + "A" + pathLength + "," + pathLength + " 0 0,1 " + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
|
||||
});
|
||||
|
||||
node.attr("transform", function(d) {
|
||||
return "translate(" + d.x + "," + d.y + ")";
|
||||
});
|
||||
}
|
||||
|
||||
function dragstarted(d) {
|
||||
d3.event.sourceEvent.stopPropagation();
|
||||
if (d && d.value && d.value.guid != that.guid) {
|
||||
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
|
||||
d.fx = d.x;
|
||||
d.fy = d.y;
|
||||
}
|
||||
}
|
||||
|
||||
function dragged(d) {
|
||||
if (d && d.value && d.value.guid != that.guid) {
|
||||
d.fx = d3.event.x;
|
||||
d.fy = d3.event.y;
|
||||
}
|
||||
}
|
||||
|
||||
function getPathColor(options) {
|
||||
return isAllEntityRelationDeleted(options) ? deletedEntityColor : activeEntityColor
|
||||
return isAllEntityRelationDeleted(options) ? deletedEntityColor : activeEntityColor;
|
||||
}
|
||||
|
||||
function isAllEntityRelationDeleted(options) {
|
||||
|
|
@ -378,193 +507,52 @@ define(['require',
|
|||
d.value = [d.value];
|
||||
}
|
||||
|
||||
return (_.findIndex(d.value, function(val) {
|
||||
if (type == "node") {
|
||||
return (val.entityStatus || val.status) == "ACTIVE"
|
||||
} else {
|
||||
return val.relationshipStatus == "ACTIVE"
|
||||
}
|
||||
}) == -1);
|
||||
return (
|
||||
_.findIndex(d.value, function(val) {
|
||||
if (type == "node") {
|
||||
return (val.entityStatus || val.status) == "ACTIVE";
|
||||
} else {
|
||||
return val.relationshipStatus == "ACTIVE";
|
||||
}
|
||||
}) == -1
|
||||
);
|
||||
}
|
||||
|
||||
// add the links and the arrows
|
||||
var path = container.append("svg:g").selectAll("path")
|
||||
.data(force.links())
|
||||
.enter().append("svg:path")
|
||||
// .attr("class", function(d) { return "link " + d.type; })
|
||||
.attr("class", "relatioship-link")
|
||||
.attr("stroke", function(d) { return getPathColor({ data: d, type: 'path' }) })
|
||||
.attr("marker-end", function(d) {
|
||||
return "url(#" + (isAllEntityRelationDeleted({ data: d }) ? "deletedLink" : "activeLink") + ")";
|
||||
});
|
||||
|
||||
// define the nodes
|
||||
var node = container.selectAll(".node")
|
||||
.data(force.nodes())
|
||||
.enter().append("g")
|
||||
.attr("class", "node")
|
||||
.on('touchstart', function(d) {
|
||||
if (d && d.value && d.value.guid != that.guid) {
|
||||
d3.event.stopPropagation();
|
||||
}
|
||||
})
|
||||
.on('mousedown', function(d) {
|
||||
if (d && d.value && d.value.guid != that.guid) {
|
||||
d3.event.stopPropagation();
|
||||
}
|
||||
})
|
||||
.on('click', function(d) {
|
||||
if (d3.event.defaultPrevented) return; // ignore drag
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
that.ui.boxClose.trigger('click');
|
||||
return;
|
||||
}
|
||||
that.toggleBoxPanel({ el: that.$('.relationship-node-details') });
|
||||
that.ui.searchNode.data({ obj: d });
|
||||
$(this).find('circle').addClass("node-detail-highlight");
|
||||
that.updateRelationshipDetails({ obj: d });
|
||||
|
||||
}).call(force.drag);
|
||||
|
||||
// add the nodes
|
||||
var circleContainer = node.append("g");
|
||||
circleContainer.on("dblclick", function(d) {
|
||||
if ((_.isArray(d.value) && d.value.length == 1) || d.value.guid) {
|
||||
var guid = _.isArray(d.value) ? _.first(d.value).guid : d.value.guid;
|
||||
Utils.setUrl({
|
||||
url: '#!/detailPage/' + guid,
|
||||
mergeBrowserUrl: false,
|
||||
urlParams: { tabActive: 'relationship' },
|
||||
trigger: true
|
||||
});
|
||||
var zoomClick = function() {
|
||||
var scaleFactor = 0.8;
|
||||
if (this.id === 'zoom_in') {
|
||||
scaleFactor = 1.3;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
circleContainer.append("circle")
|
||||
.attr("cx", 0)
|
||||
.attr("cy", 0)
|
||||
.attr("r", function(d) {
|
||||
d.radius = 25;
|
||||
return d.radius;
|
||||
})
|
||||
.attr("fill", function(d) {
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
if (isAllEntityRelationDeleted({ data: d, type: 'node' })) {
|
||||
return deletedEntityColor;
|
||||
} else {
|
||||
return selectedNodeColor;
|
||||
}
|
||||
} else if (isAllEntityRelationDeleted({ data: d, type: 'node' })) {
|
||||
return deletedEntityColor;
|
||||
} else {
|
||||
return activeEntityColor;
|
||||
}
|
||||
})
|
||||
.attr("typename", function(d) {
|
||||
return d.name;
|
||||
})
|
||||
circleContainer.append("text")
|
||||
.attr('x', 0)
|
||||
.attr('y', 0)
|
||||
.attr('dy', (25 - 17))
|
||||
.attr("text-anchor", "middle")
|
||||
.style("font-family", "FontAwesome")
|
||||
.style('font-size', function(d) { return '25px'; })
|
||||
.text(function(d) {
|
||||
var iconObj = Enums.graphIcon[d.name];
|
||||
if (iconObj && iconObj.textContent) {
|
||||
return iconObj.textContent;
|
||||
} else {
|
||||
if (d && _.isArray(d.value) && d.value.length > 1) {
|
||||
return '\uf0c5';
|
||||
} else {
|
||||
return '\uf016';
|
||||
}
|
||||
}
|
||||
})
|
||||
.attr("fill", function(d) {
|
||||
return "#fff";
|
||||
});
|
||||
var countBox = circleContainer.append('g')
|
||||
countBox.append("circle")
|
||||
.attr("cx", 18)
|
||||
.attr("cy", -20)
|
||||
.attr("r", function(d) {
|
||||
if (_.isArray(d.value) && d.value.length > 1) {
|
||||
return 10;
|
||||
}
|
||||
});
|
||||
|
||||
countBox.append("text")
|
||||
.attr('dx', 18)
|
||||
.attr('dy', -16)
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("fill", defaultEntityColor)
|
||||
.text(function(d) {
|
||||
if (_.isArray(d.value) && d.value.length > 1) {
|
||||
return d.value.length;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// add the text
|
||||
node.append("text")
|
||||
.attr("x", -15)
|
||||
.attr("y", "35")
|
||||
.text(function(d) { return d.name; });
|
||||
|
||||
// add the curvy lines
|
||||
function tick() {
|
||||
path.attr("d", function(d) {
|
||||
var diffX = d.target.x - d.source.x,
|
||||
diffY = d.target.y - d.source.y,
|
||||
|
||||
// Length of path from center of source node to center of target node
|
||||
pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY)),
|
||||
|
||||
// x and y distances from center to outside edge of target node
|
||||
offsetX = (diffX * d.target.radius) / pathLength,
|
||||
offsetY = (diffY * d.target.radius) / pathLength;
|
||||
|
||||
return "M" + d.source.x + "," + d.source.y + "A" + pathLength + "," + pathLength + " 0 0,1 " + (d.target.x - offsetX) + "," + (d.target.y - offsetY)
|
||||
});
|
||||
|
||||
node.attr("transform", function(d) {
|
||||
if (d && d.value && d.value.guid == that.guid) {
|
||||
d.x = (width / 2)
|
||||
d.y = (height / 2)
|
||||
}
|
||||
return "translate(" + d.x + "," + d.y + ")";
|
||||
});
|
||||
zoom.scaleBy(svg.transition().duration(750), scaleFactor);
|
||||
}
|
||||
|
||||
function dragstart(d) {
|
||||
d3.select(this).classed("fixed", d.fixed = true);
|
||||
}
|
||||
d3.selectAll(this.$('.lineageZoomButton')).on('click', zoomClick);
|
||||
},
|
||||
createTable: function() {
|
||||
this.entityModel = new VEntity({});
|
||||
var table = CommonViewFunction.propertyTable({ scope: this, valueObject: this.entity.relationshipAttributes, attributeDefs: this.attributeDefs });
|
||||
var table = CommonViewFunction.propertyTable({
|
||||
scope: this,
|
||||
valueObject: this.entity.relationshipAttributes,
|
||||
attributeDefs: this.attributeDefs
|
||||
});
|
||||
this.ui.relationshipDetailValue.html(table);
|
||||
Utils.togglePropertyRelationshipTableEmptyValues({
|
||||
"inputType": this.ui.noValueToggle,
|
||||
"tableEl": this.ui.relationshipDetailValue
|
||||
inputType: this.ui.noValueToggle,
|
||||
tableEl: this.ui.relationshipDetailValue
|
||||
});
|
||||
},
|
||||
relationshipViewToggle: function(checked) {
|
||||
this.ui.relationshipDetailTable.toggleClass('visible invisible');
|
||||
this.ui.relationshipSVG.toggleClass('visible invisible');
|
||||
this.ui.relationshipDetailTable.toggleClass("visible invisible");
|
||||
this.ui.relationshipSVG.toggleClass("visible invisible");
|
||||
|
||||
if (checked) {
|
||||
this.ui.zoomControl.hide();
|
||||
this.$el.addClass('auto-height');
|
||||
this.$el.addClass("auto-height");
|
||||
} else {
|
||||
this.ui.zoomControl.show();
|
||||
this.$el.removeClass('auto-height');
|
||||
this.$el.removeClass("auto-height");
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
return RelationshipLayoutView;
|
||||
});
|
||||
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
* 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",
|
||||
"backbone",
|
||||
"hbs!tmpl/graph/TypeSystemTreeView_tmpl",
|
||||
"collection/VLineageList",
|
||||
"models/VEntity",
|
||||
"LineageHelper",
|
||||
"d3",
|
||||
"dagreD3",
|
||||
"d3-tip",
|
||||
"utils/CommonViewFunction",
|
||||
"utils/Utils",
|
||||
"platform",
|
||||
"jquery-ui"
|
||||
], function(require, Backbone, TypeSystemTreeViewTmpl, VLineageList, VEntity, LineageHelper, d3, dagreD3, d3Tip, CommonViewFunction, Utils, platform) {
|
||||
"use strict";
|
||||
|
||||
/** @lends TypeSystemTreeView */
|
||||
var TypeSystemTreeView = Backbone.Marionette.LayoutView.extend({
|
||||
_viewName: "TypeSystemTreeViewTmpl",
|
||||
|
||||
template: TypeSystemTreeViewTmpl,
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
modalID: this.viewId,
|
||||
width: "100%",
|
||||
height: "300px"
|
||||
};
|
||||
},
|
||||
|
||||
/** Layout sub regions */
|
||||
regions: {
|
||||
RTypeSystemTreeViewPage: "#r_typeSystemTreeViewPage"
|
||||
},
|
||||
|
||||
/** ui selector cache */
|
||||
ui: {
|
||||
typeSystemTreeViewPage: "[data-id='typeSystemTreeViewPage']",
|
||||
boxClose: '[data-id="box-close"]',
|
||||
nodeDetailTable: '[data-id="nodeDetailTable"]',
|
||||
typeSearch: '[data-id="typeSearch"]',
|
||||
filterServiceType: '[data-id="filterServiceType"]',
|
||||
onZoomIn: '[data-id="zoom-in"]',
|
||||
onZoomOut: '[data-id="zoom-out"]',
|
||||
filterBox: ".filter-box",
|
||||
searchBox: ".search-box",
|
||||
filterToggler: '[data-id="filter-toggler"]',
|
||||
searchToggler: '[data-id="search-toggler"]',
|
||||
reset: '[data-id="reset"]',
|
||||
fullscreenToggler: '[data-id="fullScreen-toggler"]'
|
||||
},
|
||||
/** ui events hash */
|
||||
events: function() {
|
||||
var events = {};
|
||||
events["click " + this.ui.boxClose] = "toggleBoxPanel";
|
||||
events["click " + this.ui.onZoomIn] = "onClickZoomIn";
|
||||
events["click " + this.ui.onZoomOut] = "onClickZoomOut";
|
||||
events["click " + this.ui.filterToggler] = "onClickFilterToggler";
|
||||
events["click " + this.ui.searchToggler] = "onClickSearchToggler";
|
||||
events["click " + this.ui.fullscreenToggler] = "onClickFullscreenToggler";
|
||||
events["click " + this.ui.reset] = "onClickReset";
|
||||
return events;
|
||||
},
|
||||
|
||||
/**
|
||||
* @constructs
|
||||
*/
|
||||
initialize: function(options) {
|
||||
_.extend(this, _.pick(options, "entityDefCollection"));
|
||||
},
|
||||
onShow: function() {
|
||||
this.$(".fontLoader").show();
|
||||
this.initializeGraph();
|
||||
this.fetchGraphData();
|
||||
},
|
||||
onRender: function() {},
|
||||
fetchGraphData: function(options) {
|
||||
var that = this;
|
||||
var entityTypeDef = that.entityDefCollection.fullCollection.toJSON();
|
||||
this.$(".fontLoader").show();
|
||||
this.$("svg").empty();
|
||||
if (that.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
if (entityTypeDef.length) {
|
||||
that.generateData($.extend(true, {}, { data: entityTypeDef }, options)).then(function(graphObj) {
|
||||
that.createGraph();
|
||||
});
|
||||
}
|
||||
},
|
||||
generateData: function(options) {
|
||||
return new Promise(
|
||||
function(resolve, reject) {
|
||||
try {
|
||||
var that = this,
|
||||
newHashMap = {},
|
||||
styleObj = {
|
||||
fill: "none",
|
||||
stroke: "#ffb203",
|
||||
width: 3
|
||||
},
|
||||
makeNodeData = function(relationObj) {
|
||||
if (relationObj) {
|
||||
if (relationObj.updatedValues) {
|
||||
return relationObj;
|
||||
}
|
||||
var obj = _.extend(relationObj, {
|
||||
shape: "img",
|
||||
updatedValues: true,
|
||||
label: relationObj.name.trunc(18),
|
||||
toolTipLabel: relationObj.name,
|
||||
id: relationObj.guid,
|
||||
isLineage: true,
|
||||
isIncomplete: false
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
getStyleObjStr = function(styleObj) {
|
||||
return "fill:" + styleObj.fill + ";stroke:" + styleObj.stroke + ";stroke-width:" + styleObj.width;
|
||||
},
|
||||
setNode = function(guid, obj) {
|
||||
var node = that.LineageHelperRef.getNode(guid);
|
||||
if (!node) {
|
||||
var nodeData = makeNodeData(obj);
|
||||
that.LineageHelperRef.setNode(guid, nodeData);
|
||||
return nodeData;
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
},
|
||||
setEdge = function(fromNodeGuid, toNodeGuid) {
|
||||
that.LineageHelperRef.setEdge(fromNodeGuid, toNodeGuid, {
|
||||
arrowhead: "arrowPoint",
|
||||
style: getStyleObjStr(styleObj),
|
||||
styleObj: styleObj
|
||||
});
|
||||
},
|
||||
setGraphData = function(fromEntityId, toEntityId) {
|
||||
setNode(fromEntityId);
|
||||
setNode(toEntityId);
|
||||
setEdge(fromEntityId, toEntityId);
|
||||
};
|
||||
|
||||
if (options.data) {
|
||||
if (options.filter) {
|
||||
var pendingSubList = {},
|
||||
pendingSuperList = {},
|
||||
temp = {},
|
||||
doneList = {},
|
||||
traveseSubSuper = function(obj, ignoreSubTypes) {
|
||||
var fromEntityId = obj.guid;
|
||||
if (!ignoreSubTypes && obj.subTypes.length) {
|
||||
_.each(obj.subTypes, function(subType) {
|
||||
var tempObj = doneList[subType] || temp[subType];
|
||||
if (tempObj) {
|
||||
setNode(tempObj.guid, tempObj);
|
||||
setEdge(fromEntityId, tempObj.guid);
|
||||
} else {
|
||||
if (pendingSubList[subType]) {
|
||||
pendingSubList[subType].push(fromEntityId);
|
||||
} else {
|
||||
pendingSubList[subType] = [fromEntityId];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (obj.superTypes.length) {
|
||||
_.each(obj.superTypes, function(superType) {
|
||||
var tempObj = doneList[superType] || temp[superType];
|
||||
if (tempObj) {
|
||||
setNode(tempObj.guid, tempObj);
|
||||
setEdge(tempObj.guid, fromEntityId);
|
||||
if (tempObj.superTypes.length) {
|
||||
traveseSubSuper(tempObj, true);
|
||||
}
|
||||
} else {
|
||||
if (pendingSuperList[superType]) {
|
||||
pendingSuperList[superType].push(fromEntityId);
|
||||
} else {
|
||||
pendingSuperList[superType] = [fromEntityId];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
_.each(options.data, function(obj) {
|
||||
var fromEntityId = obj.guid;
|
||||
if (obj.serviceType === options.filter) {
|
||||
doneList[obj.name] = obj;
|
||||
setNode(fromEntityId, obj);
|
||||
if (pendingSubList[obj.name]) {
|
||||
_.map(pendingSubList[obj.name], function(guid) {
|
||||
setEdge(guid, fromEntityId);
|
||||
});
|
||||
delete pendingSubList[obj.name];
|
||||
}
|
||||
if (pendingSuperList[obj.name]) {
|
||||
_.map(pendingSuperList[obj.name], function(guid) {
|
||||
setEdge(fromEntityId, guid);
|
||||
});
|
||||
delete pendingSuperList[obj.name];
|
||||
}
|
||||
traveseSubSuper(obj);
|
||||
} else {
|
||||
if (pendingSubList[obj.name]) {
|
||||
setNode(fromEntityId, obj);
|
||||
doneList[obj.name] = obj;
|
||||
_.map(pendingSubList[obj.name], function(guid) {
|
||||
setEdge(guid, fromEntityId);
|
||||
});
|
||||
delete pendingSubList[obj.name];
|
||||
}
|
||||
if (pendingSuperList[obj.name]) {
|
||||
var fromEntityId = obj.guid;
|
||||
setNode(fromEntityId, obj);
|
||||
doneList[obj.name] = obj;
|
||||
_.map(pendingSuperList[obj.name], function(guid) {
|
||||
setEdge(fromEntityId, guid);
|
||||
});
|
||||
delete pendingSuperList[obj.name];
|
||||
}
|
||||
if (!doneList[obj.name]) {
|
||||
temp[obj.name] = obj;
|
||||
}
|
||||
}
|
||||
});
|
||||
pendingSubList = null;
|
||||
pendingSuperList = null;
|
||||
doneList = null;
|
||||
} else {
|
||||
var pendingList = {},
|
||||
doneList = {};
|
||||
|
||||
_.each(options.data, function(obj) {
|
||||
var fromEntityId = obj.guid;
|
||||
doneList[obj.name] = obj;
|
||||
setNode(fromEntityId, obj);
|
||||
if (pendingList[obj.name]) {
|
||||
_.map(pendingList[obj.name], function(guid) {
|
||||
setEdge(guid, fromEntityId);
|
||||
});
|
||||
delete pendingList[obj.name];
|
||||
}
|
||||
if (obj.subTypes.length) {
|
||||
_.each(obj.subTypes, function(subTypes) {
|
||||
//var subTypesObj = _.find(options.data({ name: superTypes });
|
||||
//setNode(superTypeObj.attributes.guid, superTypeObj.attributes);
|
||||
if (doneList[subTypes]) {
|
||||
setEdge(fromEntityId, doneList[subTypes].guid);
|
||||
} else {
|
||||
if (pendingList[subTypes]) {
|
||||
pendingList[subTypes].push(fromEntityId);
|
||||
} else {
|
||||
pendingList[subTypes] = [fromEntityId];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
pendingList = null;
|
||||
doneList = null;
|
||||
}
|
||||
}
|
||||
resolve(this.g);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
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 });
|
||||
},
|
||||
onClickZoomIn: function() {
|
||||
this.LineageHelperRef.zoomIn();
|
||||
},
|
||||
onClickZoomOut: function() {
|
||||
this.LineageHelperRef.zoomOut();
|
||||
},
|
||||
onClickFilterToggler: function() {
|
||||
this.toggleBoxPanel({ el: this.ui.filterBox });
|
||||
},
|
||||
onClickSearchToggler: function() {
|
||||
this.toggleBoxPanel({ el: this.ui.searchBox });
|
||||
},
|
||||
onClickReset: function() {
|
||||
this.fetchGraphData({ refresh: true });
|
||||
},
|
||||
onClickFullscreenToggler: function(e) {
|
||||
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");
|
||||
},
|
||||
updateDetails: function(data) {
|
||||
this.$("[data-id='typeName']").text(Utils.getName(data));
|
||||
delete data.id;
|
||||
//atttributes
|
||||
data["atttributes"] = (data.attributeDefs || []).map(function(obj) {
|
||||
return obj.name;
|
||||
});
|
||||
delete data.attributeDefs;
|
||||
//businessAttributes
|
||||
data["businessAttributes"] = _.keys(data.businessAttributeDefs);
|
||||
delete data.businessAttributeDefs;
|
||||
//relationshipAttributes
|
||||
data["relationshipAttributes"] = (data.relationshipAttributeDefs || []).map(function(obj) {
|
||||
return obj.name;
|
||||
});
|
||||
delete data.relationshipAttributeDefs;
|
||||
|
||||
console.log(data);
|
||||
|
||||
this.ui.nodeDetailTable.html(
|
||||
CommonViewFunction.propertyTable({
|
||||
scope: this,
|
||||
guidHyperLink: false,
|
||||
getEmptyString: function(key) {
|
||||
if (key === "subTypes" || key === "superTypes" || key === "atttributes" || key === "relationshipAttributes") {
|
||||
return "[]";
|
||||
}
|
||||
return "N/A";
|
||||
},
|
||||
valueObject: _.omit(data, ["isLineage", "isIncomplete", "label", "shape", "toolTipLabel", "updatedValues"]),
|
||||
sortBy: true
|
||||
})
|
||||
);
|
||||
},
|
||||
createGraph: function(refresh) {
|
||||
this.LineageHelperRef.createGraph();
|
||||
},
|
||||
filterData: function(value) {
|
||||
this.LineageHelperRef.refresh();
|
||||
this.fetchGraphData({ filter: value });
|
||||
},
|
||||
initializeGraph: function() {
|
||||
//ref - https://bl.ocks.org/seemantk/80613e25e9804934608ac42440562168
|
||||
var that = this,
|
||||
node = this.$("svg.main").parent()[0].getBoundingClientRect();
|
||||
this.$("svg").attr("viewBox", "0 0 " + node.width + " " + node.height);
|
||||
this.LineageHelperRef = new LineageHelper.default({
|
||||
el: this.$("svg.main")[0],
|
||||
legends: false,
|
||||
setDataManually: true,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
isShowHoverPath: true,
|
||||
zoom: true,
|
||||
fitToScreen: true,
|
||||
dagreOptions: {
|
||||
rankdir: "tb"
|
||||
},
|
||||
onNodeClick: function(d) {
|
||||
that.onClickNodeToggler();
|
||||
that.updateDetails(that.LineageHelperRef.getNode(d.clickedData, true));
|
||||
},
|
||||
beforeRender: function() {
|
||||
that.$(".fontLoader").show();
|
||||
},
|
||||
afterRender: function() {
|
||||
that.graphOptions = that.LineageHelperRef.getGraphOptions();
|
||||
that.renderTypeFilterSearch();
|
||||
that.$(".fontLoader").hide();
|
||||
return;
|
||||
}
|
||||
});
|
||||
},
|
||||
renderTypeFilterSearch: function(data) {
|
||||
var that = this;
|
||||
var searchStr = "<option></option>",
|
||||
filterStr = "<option></option>",
|
||||
tempFilteMap = {};
|
||||
var nodes = that.LineageHelperRef.getNodes();
|
||||
if (!_.isEmpty(nodes)) {
|
||||
_.each(nodes, function(obj) {
|
||||
searchStr += '<option value="' + obj.guid + '">' + obj.name + "</option>";
|
||||
if (obj.serviceType && !tempFilteMap[obj.serviceType]) {
|
||||
tempFilteMap[obj.serviceType] = obj.serviceType;
|
||||
filterStr += '<option value="' + obj.serviceType + '">' + obj.serviceType + "</option>";
|
||||
}
|
||||
});
|
||||
}
|
||||
this.ui.typeSearch.html(searchStr);
|
||||
if (!this.ui.filterServiceType.data("select2")) {
|
||||
this.ui.filterServiceType.html(filterStr);
|
||||
}
|
||||
|
||||
this.initilizeTypeFilterSearch();
|
||||
},
|
||||
initilizeTypeFilterSearch: function() {
|
||||
var that = this;
|
||||
this.ui.typeSearch
|
||||
.select2({
|
||||
closeOnSelect: true,
|
||||
placeholder: "Select Node"
|
||||
})
|
||||
.on("change.select2", function(e) {
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
var selectedNode = $('[data-id="typeSearch"]').val();
|
||||
//that.searchNodeObj.selectedNode = selectedNode;
|
||||
that.LineageHelperRef.searchNode({ guid: selectedNode });
|
||||
});
|
||||
if (!this.ui.filterServiceType.data("select2")) {
|
||||
this.ui.filterServiceType
|
||||
.select2({
|
||||
closeOnSelect: true,
|
||||
placeholder: "Select ServiceType"
|
||||
})
|
||||
.on("change.select2", function(e) {
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
var selectedNode = $('[data-id="filterServiceType"]').val();
|
||||
that.filterData(selectedNode);
|
||||
//that.searchNodeObj.selectedNode = selectedNode;
|
||||
//that.LineageHelperRef.searchNode({ guid: selectedNode });
|
||||
});
|
||||
// if (this.searchNodeObj.selectedNode) {
|
||||
// this.ui.typeSearch.val(this.searchNodeObj.selectedNode);
|
||||
// this.ui.typeSearch.trigger("change.select2");
|
||||
// }
|
||||
}
|
||||
}
|
||||
});
|
||||
return TypeSystemTreeView;
|
||||
});
|
||||
Loading…
Reference in New Issue