-
Notifications
You must be signed in to change notification settings - Fork 296
Open
Labels
Description
Hello,
I'm working with a huge dataset. My client needs to see the whole dataset that (obviously) doesn't fit a single page width. If I set a fixed width to the parent container then the scroll does not work when zooming is enabled in the ngx-graph.
Is there a way to add a horizontal scroll bar to the ngx-graph when dealing with large data?
HTML code:
<div class="space-top-16 vc-form-container" [vcProgressSpinner]="loading">
@if (loaded) {
<ngx-graph
class="mss-graph-container"
[layout]="dagreLayout"
[curve]="curve"
[links]="links"
[nodes]="nodes"
[autoZoom]="true"
[autoCenter]="true">
<ng-template #nodeTemplate let-node>
<svg
height="80"
[attr.width]="node.data.children && node.data.children.length > 0 ? '112' : '72'"
[attr.max-width]="112">
<foreignObject
height="80"
[attr.width]="node.data.children && node.data.children.length > 0 ? '112' : '72'"
[attr.max-width]="112">
<div class="vc-mss-device-node-wrapper">
<div class="vc-mss-device-node" (click)="$event.preventDefault(); showWidget(node)">
<span
class="vc-mss-device-icon material-icons"
[style.border-color]="getBorderColor()"
[style.color]="node.data.icon.color"
>{{ node.data.icon.label }}</span
>
<div
xmlns="http://www.w3.org/1999/xhtml"
class="vc-mss-device-node-text body-s-1"
[matTooltip]="node.label"
[matTooltipPosition]="'above'">
{{ node.label }} - {{ node.data.type }}
</div>
</div>
@if (node.data.children && node.data.children.length > 0) {
<div class="vc-mss-device-node">
<button
mat-icon-button
class="vc-mss-device-expand-icon"
(click)="openOrCloseNode(node); selectedNode = null">
<mat-icon>{{ node.data.expanded ? 'expand_more' : 'expand_less' }}</mat-icon>
</button>
<span>({{ node.data.children.length }})</span>
</div>
}
</div>
</foreignObject>
</svg>
</ng-template>
<ng-template #linkTemplate let-link>
<svg:g class="edge" xmlns:svg="http://www.w3.org/2000/svg">
<path class="edge line mss-device-overview-line" [attr.d]="link.line"></path>
</svg:g>
</ng-template>
</ngx-graph>
} @if (selectedNode) {
<div class="vc-mss-device-node-widget vc-form-container">
<div class="vc-mss-device-title">
<h3
class="headline-s vc-mss-device-overview-high-emphasis-color"
i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.NODE_OVERVIEW">
Node overview
</h3>
<vc-button
class="vc-mss-device-close-button"
mode="icon"
iconName="close"
iconColor="var(--text-low-emphasis)"
(trigger)="selectedNode = null"></vc-button>
</div>
<div class="vc-mss-device-item-container">
<div class="vc-mss-device-node-item vc-mss-device-overview-medium-emphasis-color">
<span class="body-m-1" i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.FULL_NAME">Full name: </span>
<span class="body-m-2">{{ selectedNode.label }}</span>
</div>
<div class="vc-mss-device-node-item">
<span
class="body-m-1 vc-mss-device-overview-medium-emphasis-color"
i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.DISCOVERED_BY"
>Discovered by:
</span>
<span class="body-m-2 vc-mss-device-overview-high-emphasis-color">{{ selectedNode.data.type }}</span>
</div>
</div>
<div class="vc-mss-device-node-action-wrapper vc-form-container">
<div class="vc-mss-device-node-action-description">
<h4 class="body-m-2" i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.PING_THE_DEVICE">Ping the device</h4>
<span class="body-s" i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.PING_DESCRIPTION"
>Packet Loss and Response Time Analyzer</span
>
</div>
<vc-button
label="Ping"
i18n-label="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.PING"
mode="basic"
(trigger)="pingDevice()"></vc-button>
</div>
<div class="vc-mss-device-node-action-wrapper vc-form-container">
<div class="vc-mss-device-node-action-description">
<h4 class="body-m-2" i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.EVENTS">Events</h4>
<span class="body-s" i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.EVENTS_DESCRIPTION"
>View related events</span
>
</div>
<vc-button
label="View"
i18n-label="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.VIEW"
mode="basic"
(trigger)="navigateToEventsSearch()"></vc-button>
</div>
<div class="vc-mss-device-node-action-wrapper vc-form-container">
<div class="vc-mss-device-node-action-description">
<h4 class="body-m-2" i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.FINDINGS">Findings</h4>
<span class="body-s" i18n="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.FINDINGS_DESCRIPTION"
>View related Findings</span
>
</div>
<vc-button
label="View"
i18n-label="@@MSS.SITE_DETAIL.TABS.DEVICE_OVERVIEW.VIEW"
mode="basic"
(trigger)="navigateToFindingsSearch()"></vc-button>
</div>
</div>
}
<div class="vc-form-container vc-mss-device-legend">
@for (type of assetTypes; track type) {
<div class="vc-mss-device-legend-item body-s-1">
<vc-icon [name]="getNodeIcon(type).label" [color]="getNodeIcon(type).color"></vc-icon>
{{ getAssetTypeLabel(type) }}
</div>
}
</div>
</div>
SCSS:
:host {
display: block;
height: 100%;
width: 100%;
.vc-mss-device-node-wrapper {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
.vc-mss-device-node {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
.vc-mss-device-icon {
display: flex;
justify-content: center;
align-items: center;
height: 36px;
width: 36px;
border: 1px solid;
border-radius: 50%;
}
.vc-mss-device-node-text {
width: 56px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.vc-mss-device-node {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
cursor: pointer;
button.vc-mss-device-expand-icon {
height: 24px !important;
width: 24px !important;
box-shadow: none !important;
.mat-icon {
height: 24px;
width: 24px;
line-height: 24px;
font-size: 24px;
}
&.mat-mdc-icon-button:not([disabled]) {
&:hover,
&:focus-visible {
border-radius: 4px !important;
background-color: var(--primary-50);
}
&:focus-visible {
outline: 1px solid var(--primary-600);
outline-offset: 1px;
}
}
}
}
}
.mss-graph-container {
display: block;
height: calc(100vh - 345px);
width: 100%;
}
.mss-device-overview-item {
cursor: pointer;
}
.mss-device-overview-line {
stroke: var(--outline);
stroke-width: 1;
}
.vc-mss-device-node-widget {
display: flex;
flex-direction: column;
gap: 16px;
position: absolute;
top: 32px;
right: 16px;
width: 430px;
height: calc(100% - 50px);
overflow: auto;
.vc-mss-device-title {
display: inline-flex;
justify-content: space-between;
align-items: flex-start;
h3 {
margin: 0;
}
.vc-mss-device-close-button {
position: relative;
top: -8px;
right: -8px;
}
}
.vc-mss-device-item-container {
display: flex;
flex-direction: column;
gap: 8px;
.vc-mss-device-node-item {
display: inline-flex;
gap: 6px;
}
}
.vc-mss-device-node-action-wrapper {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.vc-mss-device-node-action-description {
display: flex;
flex-direction: column;
gap: 8px;
h4 {
margin: 0;
}
}
}
}
.vc-mss-device-legend {
display: flex;
flex-direction: column;
gap: 8px;
position: absolute;
top: 32px;
left: 16px;
width: 150px;
background-color: var(--ghost-white);
.vc-mss-device-legend-item {
display: inline-flex;
align-items: center;
gap: 8px;
}
}
.vc-mss-device-overview-high-emphasis-color {
color: var(--text-high-emphasis);
}
.vc-mss-device-overview-medium-emphasis-color {
color: var(--text-medium-emphasis);
}
}
Thanks,