src/lib/entity/detail/sz-entity-detail-graph/sz-standalone-graph.component.ts
Embeddable Graph Component used to display a entity and its network relationships to other entities visually.
Optionally can display a embedded filter control to allow user to change the components parameters of this component.
Example :<!-- (Angular) -->
<sz-standalone-graph
filterWidth="320"
[graphIds]="graphIds"
[showPopOutIcon]="false"
[showMatchKeyControl]="false"
[showFiltersControl]="false"
[filterControlPosition]="'top-right'"
(entityClick)="onGraphEntityClick($event)"
[showMatchKeys]="true"
></sz-standalone-graph>
<!-- (WC) by attribute -->
<sz-wc-standalone-graph
filter-width="320"
graph-ids="1,1001,1002"
show-pop-out-icon="false"
show-match-key-control="false"
show-filters-control="false"
filter-control-position="top-right"
show-match-keys="true"
></sz-wc-standalone-graph>
<!-- (WC) by DOM -->
<sz-wc-standalone-graph id="sz-wc-standalone-graph"></sz-wc-standalone-graph>
<script>
document.getElementById('sz-wc-standalone-graph').graphIds = [1,1001,1002];
document.getElementById('sz-wc-standalone-graph').addEventListener('entityClick', (data) => { console.log('entity clicked on!', data); })
</script>
SzGraphComponent
AfterViewInit
selector | sz-standalone-graph |
styleUrls | ../../../graph/sz-graph.component.scss |
templateUrl | ./sz-standalone-graph.component.html |
Properties |
|
Methods |
|
Inputs |
Accessors |
constructor(_p_prefs: SzPrefsService, _p_cd: ChangeDetectorRef, _p_css: SzCSSClassService, overlay: Overlay, dialog: MatDialog, viewContainerRef: ViewContainerRef)
|
|||||||||||||||||||||
Parameters :
|
showGraphContextMenu |
Type : boolean
|
whether or not to show the built-in context menu on graph entity right-click |
showGraphEntityContextMenuOnClick |
Type : boolean
|
whether or not to trigger the built-in entity context menu on single-click instead of the default right-click |
showGraphLinkContextMenu |
Type : boolean
|
whether or not to show the built-in context menu on graph link right-click |
showGraphLinkContextMenuOnClick |
Type : boolean
|
whether or not to trigger the built-in relationship context menu on single-click instead of the default right-click |
Public hideGraphEntity | ||||||
hideGraphEntity(entityId: SzEntityIdentifier)
|
||||||
remove single node and any directly related nodes that are only related to the entity specified
Parameters :
Returns :
void
|
Public hideGraphEntityRelationships | ||||||
hideGraphEntityRelationships(entityId: SzEntityIdentifier)
|
||||||
hide all visible(expanded) entities related to a specific entity that are themselves not related to any other visible entities
Parameters :
Returns :
void
|
Public isGraphEntityRemovable | ||||||
isGraphEntityRemovable(entityId: SzEntityIdentifier)
|
||||||
can a specific entity node be removed from canvas
Parameters :
Returns :
boolean
|
ngAfterViewInit |
ngAfterViewInit()
|
Returns :
void
|
Public onFilterMatchKeyTokenSelectionScopeChanged | ||||||
onFilterMatchKeyTokenSelectionScopeChanged(scope: SzMatchKeyTokenFilterScope)
|
||||||
when the filter component's match key scope is changed from EXTRANEOUS to CORE or vice-versa
Parameters :
Returns :
void
|
Public showGraphEntityRelationships | ||||||
showGraphEntityRelationships(entityId: SzEntityIdentifier)
|
||||||
show any entities that are related to a specific entity that are currently not on the canvas
Parameters :
Returns :
void
|
Public _p_prefs |
Type : SzPrefsService
|
Public dialog |
Type : MatDialog
|
Public filterShowDataSources |
Type : string[]
|
Default value : []
|
graphLinkContextMenu |
Type : TemplateRef<any>
|
Decorators :
@ViewChild('graphLinkContextMenu')
|
graphNodeContextMenu |
Type : TemplateRef<any>
|
Decorators :
@ViewChild('graphNodeContextMenu')
|
built-in graph context menus |
Public overlay |
Type : Overlay
|
Public viewContainerRef |
Type : ViewContainerRef
|
showGraphLinkContextMenu | ||||||
getshowGraphLinkContextMenu()
|
||||||
whether or not to show the built-in context menu on graph link right-click
Returns :
boolean
|
||||||
setshowGraphLinkContextMenu(value: boolean)
|
||||||
whether or not to show the built-in context menu on graph link right-click
Parameters :
Returns :
void
|
showGraphContextMenu | ||||||
getshowGraphContextMenu()
|
||||||
whether or not to show the built-in context menu on graph entity right-click
Returns :
boolean
|
||||||
setshowGraphContextMenu(value: boolean)
|
||||||
whether or not to show the built-in context menu on graph entity right-click
Parameters :
Returns :
void
|
showGraphEntityContextMenuOnClick | ||||||
setshowGraphEntityContextMenuOnClick(value: boolean)
|
||||||
whether or not to trigger the built-in entity context menu on single-click instead of the default right-click
Parameters :
Returns :
void
|
showGraphLinkContextMenuOnClick | ||||||
setshowGraphLinkContextMenuOnClick(value: boolean)
|
||||||
whether or not to trigger the built-in relationship context menu on single-click instead of the default right-click
Parameters :
Returns :
void
|
<!-- start graph entity context menu template -->
<ng-template #graphNodeContextMenu let-entityEvt>
<ul class="graph-context-menu">
<li>#{{entityEvt?.entityId}}</li>
<li [class.disabled]="!isGraphEntityRemovable(entityEvt)" (click)="hideGraphEntity(entityEvt)">Hide Entity</li>
</ul>
</ng-template>
<!-- end graph entity context menu template -->
<!-- start graph link context menu template -->
<ng-template #graphLinkContextMenu let-linkEvt>
<ul class="graph-context-menu">
<li (click)="openWhyReportForGraphRelationship(linkEvt)">Show "Why Not" Report</li>
</ul>
</ng-template>
<!-- end graph link context menu template -->
<!-- start graph container -->
<div #graphContainer class="sz-graph-container">
<div *ngIf="showZoomControl" class="zoom-control-container"
[class.top-left]="zoomControlPosition == 'top-left'"
[class.top-right]="zoomControlPosition == 'top-right'"
[class.bottom-right]="zoomControlPosition == 'bottom-right'"
[class.bottom-left]="zoomControlPosition == 'bottom-left'">
<span><button class="zoom-out" (click)="zoomOut()"></button></span>
<input disabled="disabled" type="range" min="1" max="100" [value]="graphZoom" class="slider">
<span><button class="zoom-in" (click)="zoomIn()"></button></span>
</div>
<sz-relationship-network #graph class="sz-relationship-network-graph"
[class.filters-showing]="this.showFiltersControl"
svgViewBox="150 50 400 300"
svgPreserveAspectRatio="xMinYMid meet"
[entityIds]="graphIds"
[maxDegrees]="maxDegrees"
[buildOut]="buildOut"
[linkGravity]="5"
[highlight]="entityNodeColors"
[filter]="entityNodeFilters"
[includes]="entityMatchTokenFilter"
[expandByDefaultWhenLessThan]="expandByDefaultWhenLessThan"
[showLinkLabels]="_showLinkLabels"
[suppressL1InterLinks]="_suppressL1InterLinks"
(contextMenuClick)="onRightClick($event)"
(entityClick)="onEntityClick($event)"
(relationshipClick)="onLinkClick($event)"
(relationshipContextMenuClick)="onLinkRightClick($event)"
(noResults)="onNoResults($event)"
(onTotalRelationshipsCountUpdated)="onTotalRelationshipsCountUpdated($event)"
(onDataLoaded)="onGraphDataLoaded($event)"
(onDataUpdated)="onGraphDataUpdated($event)"
(scaleChanged)="onGraphZoom($event)"
[noMaxEntitiesLimit]="unlimitedMaxEntities"
[noMaxScopeLimit]="unlimitedMaxScope"
[maxEntities]="maxEntities"></sz-relationship-network>
<sz-graph-control *ngIf="showMatchKeyControl" class="sz-graph-control"
[showLinkLabels]="_showLinkLabels"
(optionChanged)="onOptionChange($event)"
></sz-graph-control>
<sz-graph-filter *ngIf="showFiltersControl" class="sz-graph-filter"
[ngStyle]="{'width.px': filterWidth}"
[class.top-left]="filterControlPosition == 'top-left'"
[class.top-right]="filterControlPosition == 'top-right'"
[class.bottom-right]="filterControlPosition == 'bottom-right'"
[class.bottom-left]="filterControlPosition == 'bottom-left'"
[showLinkLabels]="_showLinkLabels"
(optionChanged)="onOptionChange($event)"
(matchKeyTokenSelectionScopeChanged)="onFilterMatchKeyTokenSelectionScopeChanged($event)"
[showDataSources]="filterShowDataSources"
[showMatchKeys]="filterShowMatchKeys"
[showMatchKeyTokens]="filterShowMatchKeyTokens"
[showMatchKeyFilters]="showMatchKeyFilters"
[matchKeyTokenSelectionScope]="matchKeyTokenSelectionScope"
[showMatchKeyTokenFilters]="showMatchKeyTokenFilters"
[showMatchKeyTokenSelectAll]="showMatchKeyTokenSelectAll"
[showTooltips]="showFilterTooltips"
[showCoreMatchKeyTokenChips]="showCoreMatchKeyTokenChips"
[showExtraneousMatchKeyTokenChips]="showExtraneousMatchKeyTokenChips"
[maxEntitiesLimit]="maxEntitiesFilterLimit"
></sz-graph-filter>
<svg class="popout-icon"
[class.top-left]="popOutIconPosition == 'top-left'"
[class.top-right]="popOutIconPosition == 'top-right'"
[class.bottom-right]="popOutIconPosition == 'bottom-right'"
[class.bottom-left]="popOutIconPosition == 'bottom-left'" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 64 64"
(click)="onPopOutClick()"
*ngIf="showPopOutIcon"
enable-background="new 0 0 64 64" xml:space="preserve">
<g>
<g><g><polygon points="53,56 8,56 8,11 30,11 30,3 0,3 0,64 61,64 61,34 53,34"/></g></g>
<g><g><polygon points="42,0 50,8 33,25 39,31 56,14 64,23 64,0"/></g></g>
</g>
</svg>
</div>
<!--
showLinkLabels: {{ showLinkLabels }}<br/>
_suppressL1InterLinks: {{ _suppressL1InterLinks }}<br/>
matchKeyTokenSelectionScope: {{matchKeyTokenSelectionScope}}<br/>
filterControlPosition: "{{ filterControlPosition }}"<br/>
entityIds: {{ graphIds }}
-->
<!-- end graph container -->
../../../graph/sz-graph.component.scss
@use "../scss/theme";
:host {
height: var(--sz-large-graph-height);
display: block;
transition: height 500ms;
&.open {
.arrow {
transform: rotate(180deg);
transition: all 300ms;
}
}
&.closed {
height: var(--sz-entity-detail-section-graph-collapsed-height);
.arrow {
transition: all 300ms;
}
.sz-entity-detail-section-collapsible-card {
height: 6px;
}
sz-graph-control, .sz-graph-control {
display: none;
}
sz-relationship-network, .sz-relationship-network {
display: none;
}
}
.arrow, .icon-inline {
margin: 0 10px 0 0;
color: var(--sz-entity-detail-section-header-color);
fill: var(--sz-entity-detail-section-header-color);
}
.icon-flip {
transform: rotate(180deg);
}
sz-relationship-network {
height: 100%;
&.filters-showing {
sz-relationship-network-graph, .sz-relationship-network-graph {
width: calc(100% - 340px);
}
}
}
sz-relationship-network-graph, .sz-relationship-network-graph {
width: 100%;
height: 100%;
display: block;
background-color: #fff;
}
.popout-icon {
display: block;
bottom: 10px;
left: 10px;
position: absolute;
width: 22px;
height: 22px;
z-index: 2000;
color: var(--sz-entity-graph-overlay-color);
fill: var(--sz-entity-graph-overlay-color);
cursor: pointer;
&.top-left {
top: 10px;
left: 10px;
}
&.top-right {
top: 10px;
left: unset;
right: 10px;
}
&.bottom-left {
top: unset;
bottom: 10px;
left: 10px;
}
&.bottom-right {
top: unset;
bottom: 10px;
left: unset;
right: 10px;
}
}
sz-entity-detail-section-collapsible-card, .sz-entity-detail-section-collapsible-card {
width: 100%;
height: calc( 100% - 60px);
display: block;
background: var(--sz-entity-detail-section-graph-background);
color: var(--sz-entity-detail-section-color);
font-size: var(--sz-entity-detail-section-font-size);
line-height: var(--sz-entity-detail-section-line-height);
border-bottom: var(--sz-entity-detail-section-border-top);
border-left: var(--sz-entity-detail-section-border-left);
border-right: var(--sz-entity-detail-section-border-right);
border-bottom: var(--sz-entity-detail-section-border-bottom);
/*overflow: hidden;*/
&:last-child {
border-radius: var(--sz-entity-detail-section-border-radius);
}
}
sz-graph-container, .sz-graph-container {
width: 100%;
height: 100%;
display: block;
position: relative;
background: var(--sz-entity-detail-section-graph-background);
color: var(--sz-entity-detail-section-color);
font-size: var(--sz-entity-detail-section-font-size);
line-height: var(--sz-entity-detail-section-line-height);
border-bottom: var(--sz-entity-detail-section-border-top);
border-left: var(--sz-entity-detail-section-border-left);
border-right: var(--sz-entity-detail-section-border-right);
border-bottom: var(--sz-entity-detail-section-border-bottom);
/*overflow: hidden;*/
&:last-child {
border-radius: var(--sz-entity-detail-section-border-radius);
}
}
}
/* header */
.section-header__wrapper {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 -2px 0 0px;
/*margin: var(--sz-entity-detail-section-header-margin);*/
padding: var(--sz-entity-detail-section-header-padding);
color: var(--sz-entity-detail-section-header-color);
font-size: var(--sz-entity-detail-section-header-font-size);
font-weight: 600;
font-family: var(--sz-entity-detail-section-header-font-family);
border-radius: var(--sz-entity-detail-section-header-border-radius);
background: var(--sz-color-graph-relationships);
svg.mat-icon {
display: inline-block;
width: var(--sz-entity-detail-section-header-font-size);
height: calc( var(--sz-entity-detail-section-header-font-size) *1.15 );
stroke-width: 0;
stroke: var(--sz-entity-detail-section-header-color);
fill: var(--sz-entity-detail-section-header-color);
margin-right: .3em;
}
.section-header__right-content {
display: flex;
align-items: center;
.section-header__countLabel {
font-size: var(--sz-entity-detail-section-header-count-label-font-size);
/*font-weight: 300;*/
margin: 0 0 0 6px;
}
.section-header__count {
font-size: var(--sz-entity-detail-section-header-count-font-size);
margin: 0 4px 0 8px;
}
}
.section-header__left-content {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
max-width: 70%;
.section-header__title {
overflow: hidden;
white-space: nowrap;
width: 100%;
text-overflow: ellipsis;
}
}
}
/* control surface */
.sz-entity-detail-section-collapsible-card, .sz-entity-detail-section-collapsible-card {
position: relative;
}
sz-graph-control, .sz-graph-control, .sz-graph-filter {
background-color: var(--sz-entity-graph-control-background-color);
display: var(--sz-entity-graph-control-display);
z-index: var(--sz-entity-graph-control-z-index);
position: var(--sz-entity-graph-control-position);
height: calc( 100% - 3px);
overflow-x: hidden;
top: var(--sz-entity-graph-control-top);
left: var(--sz-entity-graph-control-left);
right: var(--sz-entity-graph-control-right);
bottom: var(--sz-entity-graph-control-bottom);
font-size: var(--sz-entity-graph-control-font-size);
color: var(--sz-entity-graph-control-color);
padding-top: var(--sz-entity-graph-control-padding-top);
padding-right: var(--sz-entity-graph-control-padding-right);
padding-bottom: var(--sz-entity-graph-control-padding-bottom);
padding-left: var(--sz-entity-graph-control-padding-left);
border: var(--sz-entity-graph-control-border);
border-top: var(--sz-entity-graph-control-border-top);
border-right: var(--sz-entity-graph-control-border-right);
border-left: var(--sz-entity-graph-control-border-left);
border-bottom: var(--sz-entity-graph-control-border-bottom);
border-bottom-left-radius: var(--sz-entity-graph-control-border-bottom-left-radius);
border-bottom-right-radius: var(--sz-entity-graph-control-border-bottom-right-radius);
border-top-left-radius: var(--sz-entity-graph-control-border-top-left-radius);
border-top-right-radius: var(--sz-entity-graph-control-border-top-right-radius);
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer */
-khtml-user-select: none; /* KHTML browsers (e.g. Konqueror) */
-webkit-user-select: none; /* Chrome, Safari, and Opera */
-webkit-touch-callout: none; /* Disable Android and iOS callouts*/
}
.sz-graph-filter {
max-width: 300px;
&.top-left {
top: 21px;
left: 0px;
right: unset;
}
&.top-right {
top: 0px;
left: unset;
right: 0px;
bottom: unset;
}
&.bottom-left {
top: unset;
bottom: 0px;
left: 0px;
right: unset;
}
&.bottom-right {
top: unset;
bottom: 0px;
left: unset;
right: 0px;
}
}
.zoom-control-container {
position: absolute;
width: theme.$sz-graph-zoom-slider-width;
top: calc(#{theme.$sz-graph-zoom-slider-width} / 2 + 30px);
left: calc(30px - (#{theme.$sz-graph-zoom-slider-width} / 2));
z-index: 100;
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-o-transform: rotate(270deg);
transform: rotate(270deg);
display: flex;
flex-direction: row;
&.top-left {
top: calc(#{theme.$sz-graph-zoom-slider-width} / 2 + 30px);
left: calc(30px - (#{theme.$sz-graph-zoom-slider-width} / 2 + 4px));
}
&.top-right {
top: calc(#{theme.$sz-graph-zoom-slider-width} / 2 + 30px);
left: unset;
right: calc(30px - (#{theme.$sz-graph-zoom-slider-width} / 2));
}
&.bottom-left {
top: unset;
bottom: calc(#{theme.$sz-graph-zoom-slider-width} / 2 + 40px);
left: calc(30px - (#{theme.$sz-graph-zoom-slider-width} / 2 + 4px));
}
&.bottom-right {
top: unset;
left: unset;
bottom: calc(#{theme.$sz-graph-zoom-slider-width} / 2 + 40px);
right: calc(30px - (#{theme.$sz-graph-zoom-slider-width} / 2));
}
button.zoom-in,
button.zoom-out {
border: 1px solid #bbb;
border-radius: 50%;
width: 18px;
height: 18px;
line-height: 18px;
font-size: 18px;
display: block;
overflow: hidden;
color: #858585;
cursor: pointer;
position: relative;
top: calc(0px - (20px / 2) + 5.5px);
font-weight: bold;
background-repeat: no-repeat;
}
a.zoom-in, button.zoom-in {
right: -3px;
background-image: url("data:image/svg+xml,%3Csvg width='100%25' height='100%25' viewBox='-4 -4 24 24' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' xmlns:serif='http://www.serif.com/' style='fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;'%3E%3Cg%3E%3Crect x='7' y='0' width='6' height='20' style='fill:%23707070;'/%3E%3C/g%3E%3Cg%3E%3Crect x='0' y='7' width='20' height='6' style='fill:%23707070;'/%3E%3C/g%3E%3C/svg%3E");
background-position: 1px 1px;
background-size: 12px;
}
a.zoom-out, button.zoom-out {
right: 3px;
background-image: url("data:image/svg+xml,%3Csvg width='100%25' height='100%25' viewBox='0 5 20 20' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' xmlns:serif='http://www.serif.com/' style='fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;'%3E%3Crect x='7' y='0' width='6' height='20' style='fill: %23707070'/%3E%3C/svg%3E");
background-position: 2px 3px;
background-size: 12px 13px;
}
}
.slider {
-webkit-appearance: none;
width: 100%;
height: 5px;
border-radius: 1px;
background-color: #fff;
outline: solid 1px #707070;
/*opacity: 0.7;*/
-webkit-transition: .2s;
transition: opacity .2s;
background-image: url("data:image/svg+xml,%3Csvg viewBox='25 -25 250 150' xmlns='http://www.w3.org/2000/svg' fill='%23bbbbbb'%3E%3Ccircle cx='50' cy='50' r='50'/%3E%3C/svg%3E");
background-repeat: repeat-x;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 12px;
height: 12px;
border-radius: 1px;
background: #707070;
border: 1px solid #707070;
cursor: default;
}
.slider::-moz-range-thumb {
width: 14px;
height: 14px;
border-radius: 50%;
background: #7a7a7a;
cursor: default;
}