Angular 계층형 그리드 열 고정
열 또는 여러 열을 Angular UI Grid의 왼쪽 또는 오른쪽에 고정할 수 있습니다. Ignite UI for Angular의 열 고정을 사용하면 최종 사용자가 특정 열 순서로 열을 잠글 수 있으므로 계층적 Grid를 수평으로 스크롤하는 동안 해당 열을 볼 수 있습니다. Material UI Grid에는 내장된 열 고정 UI가 있어 계층적 Grid의 도구 모음을 통해 열의 고정 상태를 변경할 수 있습니다. 또한 사용자 지정 UI를 정의하고 Column Pinning API를 통해 열의 고정 상태를 변경할 수 있습니다.
Angular Hierarchical Grid 열 고정 예제
import { Component, OnInit } from '@angular/core' ;
import { CUSTOMERS } from '../../data/hierarchical-data' ;
import { ActivatedRoute } from '@angular/router' ;
import { NgClass } from '@angular/common' ;
import { IgxHierarchicalGridComponent, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxColumnComponent, IgxRowIslandComponent } from 'igniteui-angular' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
@Component ({
selector : 'app-hierarchical-grid-toolbar-pinning' ,
styleUrls : ['./hierarchical-grid-toolbar-pinning.component.scss' ],
templateUrl : 'hierarchical-grid-toolbar-pinning.component.html' ,
imports : [NgClass, IgxHierarchicalGridComponent, IgxPreventDocumentScrollDirective, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxColumnComponent, IgxRowIslandComponent]
})
export class HGridToolbarPinningComponent implements OnInit {
public localdata;
public useDarkTheme: boolean = false ;
constructor (private activatedRoute: ActivatedRoute ) {
this .localdata = CUSTOMERS;
}
public ngOnInit(): void {
this .activatedRoute.queryParams.subscribe(params => {
this .useDarkTheme = params.dark === 'true' ;
});
}
}
ts コピー <div [ngClass ]="{'grid__wrapper': true, 'dark-theme': useDarkTheme }" >
<igx-hierarchical-grid [igxPreventDocumentScroll ]="true" class ="hierarchicalGrid" [data ]="localdata" [autoGenerate ]="false"
[height ]="'100%'" [width ]="'100%'" #hierarchicalGrid >
<igx-grid-toolbar >
<igx-grid-toolbar-actions >
<igx-grid-toolbar-pinning > </igx-grid-toolbar-pinning >
</igx-grid-toolbar-actions >
</igx-grid-toolbar >
<igx-column field ="CompanyName" header ="Company Name" width ="200px" [pinned ]="true" > </igx-column >
<igx-column field ="ContactName" header ="Contact Name" width ="150px" > </igx-column >
<igx-column field ="ContactTitle" header ="Contact Title" width ="200px" > </igx-column >
<igx-column field ="Address" width ="200px" > </igx-column >
<igx-column field ="City" width ="150px" > </igx-column >
<igx-column field ="PostalCode" header ="Postal Code" width ="150px" > </igx-column >
<igx-column field ="Country" width ="150px" > </igx-column >
<igx-column field ="Phone" width ="150px" > </igx-column >
<igx-column field ="Fax" width ="150px" > </igx-column >
<igx-row-island [height ]="null" [key ]="'Orders'" [autoGenerate ]="false" >
<igx-column field ="OrderDate" header ="Order Date" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="RequiredDate" header ="Required Date" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="ShippedDate" header ="Shipped Date" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="ShipVia" header ="Ship Via" width ="150px" > </igx-column >
<igx-column field ="Freight" width ="150px" > </igx-column >
<igx-column field ="ShipName" header ="Ship Name" width ="200px" [pinned ]="true" > </igx-column >
<igx-column field ="ShipAddress" header ="Ship Address" width ="150px" > </igx-column >
<igx-column field ="ShipCity" header ="Ship City" width ="150px" > </igx-column >
<igx-column field ="ShipPostalCode" header ="Ship Postal Code" width ="150px" > </igx-column >
<igx-column field ="ShipCountry" header ="Ship Country" width ="150px" > </igx-column >
<igx-row-island [height ]="null" [key ]="'OrderDetails'" [autoGenerate ]="false" >
<igx-column field ="UnitPrice" header ="Unit Price" width ="150px" > </igx-column >
<igx-column field ="Quantity" width ="150px" > </igx-column >
<igx-column field ="Discount" width ="150px" > </igx-column >
<igx-column field ="Weight" width ="150px" > </igx-column >
<igx-column field ="Length" width ="150px" > </igx-column >
<igx-column field ="TotalPrice" width ="150px" > </igx-column >
</igx-row-island >
</igx-row-island >
</igx-hierarchical-grid >
</div >
html コピー :host ::ng-deep .title {
width: 100% ;
}
:host {
height : 110vh ;
}
.grid__wrapper {
margin : 0 auto 4rem ;
padding : 1rem ;
height : 100% ;
}
scss コピー
이 샘플이 마음에 드시나요? 전체 Ignite UI for Angular 툴킷에 액세스하고 몇 분 안에 나만의 앱을 구축해 보세요. 무료로 다운로드하세요.
열 고정 API
기둥 고정은 다음을 통해 제어됩니다. pinned
의 입력 igx-column
. 고정된 열은 기본적으로 계층적 그리드의 왼쪽에 렌더링되며 계층적 그리드 본문에서 고정 해제된 열의 가로 스크롤을 통해 고정된 상태로 유지됩니다.
<igx-hierarchical-grid class ="hgrid" [data ]="localdata" [autoGenerate ]="false"
[height ]="'600px'" [width ]="'800px'" #hierarchicalGrid >
<igx-column [field ]="Artist" [width ]="200px" [pinned ]="true" > </igx-column >
<igx-column [field ]="Debut" [width ]="200px" > </igx-column >
</igx-hierarchical-grid >
html
또한 Hierarchical Grid의 pinColumn
또는 IgxHierarchicalGridComponent
의 unpinColumn
메소드를 사용하여 필드 이름으로 열을 고정하거나 고정 해제할 수도 있습니다.
this .hierarchicalGrid.pinColumn('Artist' );
this .hierarchicalGrid.unpinColumn('Debut' );
typescript
두 메서드 모두 해당 작업의 성공 여부를 나타내는 부울 값을 반환합니다. 일반적으로 실패하는 이유는 열이 이미 원하는 상태에 있기 때문입니다.
열은 가장 오른쪽에 고정된 열의 오른쪽에 고정되어 있습니다. 고정된 열의 순서를 변경하려면 columnPin
이벤트를 구독하고 이벤트 인수의 insertAtIndex
속성을 원하는 위치 인덱스로 변경하면 됩니다.
<igx-hierarchical-grid class ="hgrid" [data ]="localdata" [autoGenerate ]="false"
[height ]="'600px'" [width ]="'800px'"
(columnPin )="columnPinning($event)" #hierarchicalGrid >
</igx-hierarchical-grid >
html
public columnPinning (event ) {
if (event.column.field === 'Artist' ) {
event.insertAtIndex = 0 ;
}
}
typescript
고정 위치
pinning
구성 옵션을 통해 열 고정 위치를 변경할 수 있습니다. 열 위치를 시작 또는 끝으로 설정할 수 있습니다. 끝으로 설정하면 열이 고정 해제된 열 뒤의 그리드 끝에서 렌더링됩니다. 고정되지 않은 열은 가로로 스크롤할 수 있지만 고정된 열은 오른쪽에 고정된 상태로 유지됩니다.
<igx-hierarchical-grid #grid1 [data ]="data" [autoGenerate ]="true" [pinning ]="pinningConfig" > </igx-hierarchical-grid >
html
public pinningConfig: IPinningConfig = { columns : ColumnPinningPosition.End };
typescript
데모
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core' ;
import { ColumnPinningPosition, IgxColumnComponent, IgxHierarchicalGridComponent, IPinningConfig, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxCellTemplateDirective, IgxTooltipTargetDirective, IgxTooltipDirective, IgxAvatarComponent, IgxCellHeaderTemplateDirective, IgxIconComponent, IgxRowIslandComponent } from 'igniteui-angular' ;
import { employeesData } from '../../data/employeesData' ;
import { athletesData } from '../../data/athletesData' ;
import { DatePipe } from '@angular/common' ;
@Component ({
encapsulation : ViewEncapsulation.None,
providers : [],
selector : 'hierarchical-grid-sample' ,
styleUrls : ['hierarchical-grid-right-pinning.component.scss' ],
templateUrl : 'hierarchical-grid-right-pinning.component.html' ,
imports : [IgxHierarchicalGridComponent, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxColumnComponent, IgxCellTemplateDirective, IgxTooltipTargetDirective, IgxTooltipDirective, IgxAvatarComponent, IgxCellHeaderTemplateDirective, IgxIconComponent, IgxRowIslandComponent, DatePipe]
})
export class HierarchicalGridRightPinningSampleComponent implements OnInit {
@ViewChild ('grid1' , { static : true })
public grid1: IgxHierarchicalGridComponent;
public data: any [];
public employeesData: any [];
public columns: any [];
public pinningConfig: IPinningConfig = { columns : ColumnPinningPosition.End };
private _columnsPinned = true ;
public ngOnInit(): void {
this .data = athletesData;
this .employeesData = employeesData;
let i = 0 ;
this .data.forEach((x ) => {
x.FirstPlaces = Math .floor(Math .random() * Math .floor(3 ));
x.SecondPlaces = Math .floor(Math .random() * Math .floor(4 ));
x.ThirdPlaces = Math .floor(Math .random() * Math .floor(5 ));
x.RegistrationDate = this .generateReadableDate(x.Registered);
x.Birthday = this .generateReadableDate(this .employeesData[i].birthday);
x.Sponsor = this .employeesData[i].company;
x.AgentData = [this .employeesData[i]];
i++;
});
}
public toggleColumn(col: IgxColumnComponent): void {
col.pinned ? col.unpin() : col.pin();
}
public get columnsPinned (): boolean {
return this ._columnsPinned;
}
public set columnsPinned (pinned ) {
this ._columnsPinned = !this ._columnsPinned;
}
private generateReadableDate(timestamp: string ): Date {
let dateObj = new Date (timestamp);
if (isNaN (dateObj.getTime())) {
dateObj = new Date (timestamp.split(' ' )[0 ]);
}
return dateObj;
}
}
ts コピー <div class ="grid__wrapper" >
<igx-hierarchical-grid #grid1 [data ]="data" [width ]="'100%'" [height ]="'480px'" [pinning ]="pinningConfig" [autoGenerate ]="false" >
<igx-grid-toolbar >
<igx-grid-toolbar-actions >
<igx-grid-toolbar-pinning > </igx-grid-toolbar-pinning >
</igx-grid-toolbar-actions >
</igx-grid-toolbar >
<igx-column field ="CountryName" header ="Team" width ="88" >
<ng-template igxCell let-cell ="cell" >
<div class ="cell__inner country-cell" >
<img [src ]="cell.row.data.CountryFlag" class ="country-flag" #target ="tooltipTarget" [igxTooltipTarget ]="tooltipRef" >
<div #tooltipRef ="tooltip" igxTooltip >
{{ cell.row.data.CountryName }}
</div >
</div >
</ng-template >
</igx-column >
<igx-column field ="Avatar" header ="Photo" dataType ="string" width ="80" [disablePinning ]="true" >
<ng-template igxCell let-cell ="cell" >
<div class ="cell__inner avatar-cell" >
<igx-avatar [src ]="cell.row.data.Avatar" shape ="circle" size ="small" > </igx-avatar >
</div >
</ng-template >
</igx-column >
<igx-column field ="Name" header ="Name" [disablePinning ]="true" > </igx-column >
<igx-column field ="AthleteNumber" header ="Number" > </igx-column >
<igx-column field ="BeatsPerMinute" header ="BPM" > </igx-column >
<igx-column field ="TopSpeed" header ="Top Speed" > </igx-column >
<igx-column field ="TrackProgress" header ="Track Progress" [disablePinning ]="true" > </igx-column >
<igx-column field ="RegistrationDate" header ="Date of Registration" width ="170" [disablePinning ]="true" >
<ng-template igxCell let-cell >
{{ cell | date:'longDate' }}
</ng-template >
</igx-column >
<igx-column field ="Birthday" header ="Birthday" width ="170" [disablePinning ]="true" >
<ng-template igxCell let-cell >
{{ cell | date:'longDate' }}
</ng-template >
</igx-column >
<igx-column field ="Sponsor" header ="Sponsor Company" width ="160" > </igx-column >
<igx-column #goldColumn field ="FirstPlaces" header ="Gold" width ="110" [pinned ]="true" >
<ng-template igxHeader >
<div class ="title-inner" >
<span style ="float:left" > {{ goldColumn.header }}</span >
<igx-icon [style.color ]="'#d2c206'" > emoji_events</igx-icon >
</div >
</ng-template >
</igx-column >
<igx-column #silverColumn field ="SecondPlaces" header ="Silver" width ="110" [pinned ]="true" >
<ng-template igxHeader >
<div class ="title-inner" >
<span style ="float:left" > {{ silverColumn.header }}</span >
<igx-icon [style.color ]="'#c5c5c5'" > emoji_events</igx-icon >
</div >
</ng-template >
</igx-column >
<igx-column #bronzeColumn field ="ThirdPlaces" header ="Bronze" width ="110" [pinned ]="true" >
<ng-template igxHeader >
<div class ="title-inner" >
<span style ="float:left" > {{ bronzeColumn.header }}</span >
<igx-icon [style.color ]="'#bb8b1d'" > emoji_events</igx-icon >
</div >
</ng-template >
</igx-column >
<igx-row-island [height ]="null" [key ]="'AgentData'" [autoGenerate ]="false" [pinning ]="pinningConfig" >
<igx-column field ="avatar" header ="Agent's Photo" width ="80" >
<ng-template igxCell let-cell ="cell" >
<div class ="cell__inner avatar-cell" >
<igx-avatar [src ]="cell.row.data.avatar" shape ="circle" size ="small" > </igx-avatar >
</div >
</ng-template >
</igx-column >
<igx-column field ="name" header ="Agent" > </igx-column >
<igx-column field ="company" header ="Associated Company" width ="160" > </igx-column >
<igx-column field ="email" header ="Work E-mail" width ="250" > </igx-column >
<igx-column field ="work_phone" header ="Work Phone" width ="160" > </igx-column >
<igx-column field ="street" header ="Street" width ="200" [pinned ]="true" > </igx-column >
<igx-column field ="city" header ="City" [pinned ]="true" > </igx-column >
<igx-column field ="post_code" header ="Post Code" > </igx-column >
<igx-column field ="state" header ="State" > </igx-column >
<igx-column field ="country" header ="Country" [pinned ]="true" > </igx-column >
<igx-column field ="refferred_by" header ="Reffered by" > </igx-column >
</igx-row-island >
</igx-hierarchical-grid >
</div >
html コピー .title-inner {
display : flex;
justify-content : space-between;
align-items : center;
}
.grid__wrapper {
margin : 0 auto;
padding : 16px ;
}
img .country-flag {
width : 35px ;
height : 20px ;
}
scss コピー
사용자 정의 열 고정 UI
관련 API를 통해 사용자 정의 UI를 정의하고 열의 핀 상태를 변경할 수 있습니다.
도구 모음 대신 최종 사용자가 클릭하여 특정 열의 핀 상태를 변경할 수 있는 열 헤더에 핀 아이콘을 정의한다고 가정해 보겠습니다. 이는 사용자 정의 아이콘이 있는 열의 헤더 템플릿을 생성하여 수행할 수 있습니다.
<ng-template igxHeader let-column #pinTemplate >
<div class ="title-inner" >
<span style ="float:left" > {{column.header || column.field}}</span >
<igx-icon class ="pin-icon" [class.pinned ]="column.pinned" [class.unpinned ]="!column.pinned" fontSet ="fas" name ="fa-thumbtack"
(click )="toggleColumn(column)" > </igx-icon >
</div >
</ng-template >
<igx-hierarchical-grid class ="hierarchicalGrid" [data ]="localdata" [autoGenerate ]="false"
[height ]="'500px'" [width ]="'100%'" #hierarchicalGrid >
<igx-column field ="CompanyName" header ="Company Name" [headerTemplate ]="pinTemplate" width ="200px" [pinned ]="true" > </igx-column >
<igx-column field ="ContactName" header ="Contact Name" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="ContactTitle" header ="Contact Title" [headerTemplate ]="pinTemplate" width ="200px" > </igx-column >
<igx-row-island [key ]="'Orders'" [autoGenerate ]="false" >
<igx-column field ="OrderDate" header ="Order Date" [headerTemplate ]="pinTemplate" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="RequiredDate" header ="Required Date" [headerTemplate ]="pinTemplate" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="ShippedDate" header ="Shipped Date" [headerTemplate ]="pinTemplate" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="ShipVia" header ="Ship Via" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-row-island [key ]="'OrderDetails'" [autoGenerate ]="false" >
<igx-column field ="UnitPrice" header ="Unit Price" width ="150px" > </igx-column >
<igx-column field ="Quantity" width ="150px" > </igx-column >
<igx-column field ="Discount" width ="150px" > </igx-column >
</igx-row-island >
</igx-row-island >
</igx-hierarchical-grid >
html
사용자 정의 아이콘을 클릭하면 해당 열의 API 메소드를 사용하여 관련 열의 고정 상태를 변경할 수 있습니다.
public toggleColumn (col: ColumnType ) {
col.pinned ? col.unpin() : col.pin();
}
typescript
데모
import { AfterViewInit, ChangeDetectorRef, Component } from '@angular/core' ;
import { ColumnType, IgxIconService, IgxCellHeaderTemplateDirective, IgxIconComponent, IgxHierarchicalGridComponent, IgxColumnComponent, IgxRowIslandComponent } from 'igniteui-angular' ;
import { CUSTOMERS } from '../../data/hierarchical-data' ;
import { icons } from "../../services/svgIcons" ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
const FILTERING_ICONS_FONT_SET = 'filtering-icons' ;
@Component ({
selector : 'app-hierarchical-grid-pinning' ,
styleUrls : ['./hierarchical-grid-pinning.component.scss' ],
templateUrl : 'hierarchical-grid-pinning.component.html' ,
imports : [IgxCellHeaderTemplateDirective, IgxIconComponent, IgxHierarchicalGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxRowIslandComponent]
})
export class HGridPinningSampleComponent implements AfterViewInit {
public localdata;
constructor (private cdr: ChangeDetectorRef, private iconService: IgxIconService ) {
this .localdata = CUSTOMERS;
}
public ngAfterViewInit ( ) {
const pinnedIcons = icons.filter(icon => icon.name === "pin" || icon.name === "unpin" );
pinnedIcons.forEach(icon => {
if (!this .iconService.isSvgIconCached(icon.name, FILTERING_ICONS_FONT_SET)) {
this .iconService.addSvgIconFromText(icon.name, icon.value, FILTERING_ICONS_FONT_SET);
}
});
}
public toggleColumn (column: ColumnType ) {
column.pinned ? column.unpin() : column.pin();
this .cdr.detectChanges();
}
}
ts コピー <div class ="grid__wrapper" >
<ng-template igxHeader let-column #pinTemplate >
<div class ="title-inner" >
<span class ="header-text" > {{column.header || column.field}}</span >
<igx-icon class ="pin-icon" [class.pinned ]="column.pinned" [class.unpinned ]="!column.pinned"
family ="filtering-icons" name ="{{column.pinned ? 'unpin' : 'pin'}}" (click )="toggleColumn(column)" >
</igx-icon >
</div >
</ng-template >
<igx-hierarchical-grid [igxPreventDocumentScroll ]="true" class ="hierarchicalGrid" [data ]="localdata" [autoGenerate ]="false"
[height ]="'480px'" [width ]="'100%'" #hierarchicalGrid >
<igx-column field ="CompanyName" header ="Company Name" [headerTemplate ]="pinTemplate" width ="200px" [pinned ]="true" > </igx-column >
<igx-column field ="ContactName" header ="Contact Name" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="ContactTitle" header ="Contact Title" [headerTemplate ]="pinTemplate" width ="200px" > </igx-column >
<igx-column field ="Address" [headerTemplate ]="pinTemplate" width ="200px" > </igx-column >
<igx-column field ="City" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="PostalCode" header ="Postal Code" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="Country" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="Phone" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="Fax" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-row-island [height ]="null" [key ]="'Orders'" [autoGenerate ]="false" >
<igx-column field ="OrderDate" header ="Order Date" [headerTemplate ]="pinTemplate" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="RequiredDate" header ="Required Date" [headerTemplate ]="pinTemplate" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="ShippedDate" header ="Shipped Date" [headerTemplate ]="pinTemplate" [dataType ]="'date'" width ="150px" > </igx-column >
<igx-column field ="ShipVia" header ="Ship Via" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="Freight" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="ShipName" header ="Ship Name" [headerTemplate ]="pinTemplate" width ="200px" [pinned ]="true" > </igx-column >
<igx-column field ="ShipAddress" header ="Ship Address" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="ShipCity" header ="Ship City" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="ShipPostalCode" header ="Ship Postal Code" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-column field ="ShipCountry" header ="Ship Country" [headerTemplate ]="pinTemplate" width ="150px" > </igx-column >
<igx-row-island [height ]="null" [key ]="'OrderDetails'" [autoGenerate ]="false" >
<igx-column field ="UnitPrice" header ="Unit Price" width ="150px" > </igx-column >
<igx-column field ="Quantity" width ="150px" > </igx-column >
<igx-column field ="Discount" width ="150px" > </igx-column >
</igx-row-island >
</igx-row-island >
</igx-hierarchical-grid >
</div >
html コピー .grid__wrapper {
margin : 0 auto;
padding : 16px ;
}
.title-inner {
display : flex;
justify-content : space-between;
align-items : center;
}
.header-text {
white-space : nowrap;
overflow : hidden;
text-overflow : ellipsis;
}
.pin-icon {
margin-left : 8px ;
cursor : pointer;
display : flex;
align-items : center;
}
.pinned {
color : #444 ;
&:hover {
color : #999 ;
}
}
.unpinned {
color : #999 ;
&:hover {
color : #444 ;
}
}
scss コピー
고정 제한
열 너비를 백분율(%)로 설정하면 고정된 열이 있을 때 계층적 격자 본문과 머리글 콘텐츠가 잘못 정렬됩니다. 열 고정이 올바르게 작동하려면 열 너비가 픽셀(px) 단위이거나 계층 그리드에 의해 자동 할당되어야 합니다.
API 참조
추가 리소스
우리 커뮤니티는 활동적이며 항상 새로운 아이디어를 환영합니다.