Web Components 차트는 수백만 개의 데이터 포인트를 렌더링하고 몇 밀리초마다 업데이트하는 고성능에 최적화되어 있습니다. 그러나 차트의 성능에 영향을 주는 몇 가지 차트 기능이 있으며 응용 프로그램에서 성능을 최적화할 때 이러한 기능을 고려해야 합니다. 이 항목에서는 응용 프로그램에서 Web Components 차트가 가능한 한 빨리 작동하도록 안내합니다.
Web Components Chart Performance Examples
다음 예제에서는 Web Components 차트의 두 가지 고성능 시나리오를 보여 줍니다.
Web Components Chart with High-Frequency
빈도가 높은 시나리오에서 Web Components 차트는 실시간으로 또는 지정된 밀리초 간격으로 업데이트되는 데이터 항목을 렌더링할 수 있습니다. 지연, 화면 깜박임, 시각적 지연을 경험하지 않으며 터치 장치에서 차트와 상호 작용할 때도 마찬가지입니다. 다음 샘플에서는 고주파 시나리오를 보여 줍니다 IgcCategoryChartComponent.
EXAMPLE
DATA
TS
HTML
CSS
exportclassCategoryChartSharedData{
publicstatic generateItems(startValue: number, maxPoints: number, useShortLabels?: boolean): any[] {
const data: any[] = [];
let value = startValue;
for (let i = 0; i <= maxPoints; i++) {
value += Math.random() * 4.0 - 2.0;
const v = Math.round(value);
let l = i.toString();
if (useShortLabels) {
l = this.toShortString(i);
}
data.push({ Label: l, Value: v });
}
return data;
}
publicstatic getTemperatures(startValue: number, startYear: number, endYear: number): any[] {
const data: any[] = [];
let value = startValue;
for (let i = startYear; i <= endYear; i++) {
value += (Math.random() - 0.5) * 0.5;
const v = Math.abs(Math.round(value * 10) / 10);
data.push({ Label: i.toString(), Value: v });
}
return data;
}
publicstatic getLastItem(array: any[]): any {
if (array.length === 0) {
returnnull;
}
return array[array.length - 1];
}
publicstatic getNewItem(array: any[], index: number): any {
const lastItem = this.getLastItem(array);
const newValue = lastItem.Value + Math.random() * 4.0 - 2.0;
return { Label: index.toString(), Value: newValue };
}
publicstatic toShortString(largeValue: number): string {
let roundValue: number;
if (largeValue >= 1000000) {
roundValue = Math.round(largeValue / 100000) / 10;
return roundValue + "m";
}
if (largeValue >= 1000) {
roundValue = Math.round(largeValue / 100) / 10;
return roundValue + "k";
}
roundValue = Math.round(largeValue);
return roundValue + "";
}
publicstatic addDays(date: Date, days: number): Date {
date.setDate(date.getDate() + days);
return date;
}
}
ts
import { IgcCategoryChartModule } from'igniteui-webcomponents-charts';
import { IgcCategoryChartComponent } from'igniteui-webcomponents-charts';
import { ModuleManager } from'igniteui-webcomponents-core';
import { CategoryChartSharedData } from'./CategoryChartSharedData';
ModuleManager.register(IgcCategoryChartModule);
exportclassCategoryChartHighFrequency{
private chart: IgcCategoryChartComponent;
public dataIndex: number = 0;
public dataPoints: number = 100000;
public data: any[] = [];
public refreshMilliseconds: number = 10;
public interval: number = -1;
private dataInfoLabel: HTMLLabelElement;
private refreshInfoLabel: HTMLLabelElement;
private timerTickButton : HTMLButtonElement;
private shouldTick: boolean = false;
constructor() {
this.onRefreshFrequencyChanged = this.onRefreshFrequencyChanged.bind(this);
this.onDataGenerateClick = this.onDataGenerateClick.bind(this);
this.onTimerButtonClick = this.onTimerButtonClick.bind(this);
this.onDataPointsChanged = this.onDataPointsChanged.bind(this);
this.tick = this.tick.bind(this);
this.chart = document.getElementById('chart') as IgcCategoryChartComponent;
this.data = CategoryChartSharedData.generateItems(100, this.dataPoints, false);
this.chart.dataSource = this.data;
this.onChartInit();
let slider1 = document.getElementById('slider') as HTMLInputElement;
slider1.value = this.dataPoints.toString();
slider1!.addEventListener('change', this.onDataPointsChanged);
this.refreshInfoLabel = document.getElementById('refreshInfoLabel') as HTMLLabelElement;
this.refreshInfoLabel.textContent = (this.refreshMilliseconds / 1000).toFixed(3) + 's';
let refreshSlider = document.getElementById('refreshSlider') as HTMLInputElement;
refreshSlider.value = this.refreshMilliseconds.toString();
refreshSlider!.addEventListener('change', this.onRefreshFrequencyChanged);
this.dataInfoLabel = document.getElementById('dataInfoLabel') as HTMLLabelElement;
this.dataInfoLabel.textContent = CategoryChartSharedData.toShortString(this.dataPoints);
let dataGenerate1 = document.getElementById('dataGenerate') as HTMLInputElement;
dataGenerate1!.addEventListener('click', this.onDataGenerateClick);
this.timerTickButton = document.getElementById('timerButton') as HTMLButtonElement;
this.timerTickButton!.addEventListener('click', this.onTimerButtonClick);
}
publiccomponentWillUnmount() {
if (this.interval >= 0) {
window.clearInterval(this.interval);
this.interval = -1;
}
}
public onChartInit(): void {
this.setupInterval();
}
publiconDataGenerateClick() {
this.data = CategoryChartSharedData.generateItems(100, this.dataPoints, false);
this.dataIndex = this.data.length;
this.chart = document.getElementById('chart') as IgcCategoryChartComponent;
this.chart.dataSource = this.data;
}
publiconTimerButtonClick() {
this.shouldTick = !this.shouldTick;
if (this.shouldTick) {
this.timerTickButton.textContent = "Stop";
}
else {
this.timerTickButton.textContent = "Start";
}
}
public onDataPointsChanged = (e: any) => {
let num: number = parseInt(e.target.value, 10);
if (isNaN(num)) {
num = 10000;
}
if (num < 10000) {
num = 10000;
}
if (num > 1000000) {
num = 1000000;
}
const info = CategoryChartSharedData.toShortString(num);
this.dataInfoLabel.textContent = info;
this.dataPoints = num;
}
public onRefreshFrequencyChanged = (e: any) => {
let num: number = parseInt(e.target.value, 10);
if (isNaN(num)) {
num = 10;
}
if (num < 10) {
num = 10;
}
if (num > 500) {
num = 500;
}
this.refreshMilliseconds = num;
this.refreshInfoLabel.textContent = (this.refreshMilliseconds / 1000).toFixed(3) + 's';
this.setupInterval();
}
public setupInterval(): void {
if (this.interval >= 0) {
window.clearInterval(this.interval);
this.interval = -1;
}
this.interval = window.setInterval(() =>this.tick(),
this.refreshMilliseconds);
}
public tick(): void {
if (this.shouldTick) {
this.dataIndex++;
const oldItem = this.data[0];
const newItem = CategoryChartSharedData.getNewItem(this.data, this.dataIndex);
// updating data source and notifying category chartthis.data.push(newItem);
this.chart.notifyInsertItem(this.data, this.data.length - 1, newItem);
this.data.shift();
this.chart.notifyRemoveItem(this.data, 0, oldItem);
}
}
}
new CategoryChartHighFrequency();
ts
<!DOCTYPE html><html><head><title>CategoryChartHighFrequency</title><metacharset="UTF-8" /><linkrel="shortcut icon"href="https://static.infragistics.com/xplatform/images/browsers/wc.png" ><linkrel="stylesheet"href="https://fonts.googleapis.com/icon?family=Material+Icons" /><linkrel="stylesheet"href="https://fonts.googleapis.com/css?family=Kanit&display=swap" /><linkrel="stylesheet"href="https://fonts.googleapis.com/css?family=Titillium Web" /><linkrel="stylesheet"href="https://static.infragistics.com/xplatform/css/samples/shared.v8.css"type="text/css" /></head><body><divid="root"><divclass="container sample"><divclass="options horizontal"><labelclass="options-label">Refresh: </label><buttonid="timerButton">Start</button><labelclass="options-value"id="refreshInfoLabel"></label><inputclass="options-slider"id="refreshSlider"type="range"min="10"max="500"></input><buttonclass="options-button"id="dataGenerate">Generate</button><labelclass="options-label">Points: </label><labelclass="options-value"id="dataInfoLabel" >100000 </label><inputclass="options-slider"id="slider"type="range"min="10000"max="1000000"step="1000"value="100000"></input></div><igc-category-chartid="chart"chart-type="Line"width="100%"height="calc(100% - 3rem)"y-axis-extent="60"x-axis-enhanced-interval-prefer-more-category-labels="false"should-consider-auto-rotation-for-initial-labels="false"should-auto-expand-margin-for-initial-labels="false"crosshairs-display-mode="None"auto-margin-and-angle-update-mode="None"marker-types="None" ></igc-category-chart></div></div><!-- This script is needed only for parcel and it will be excluded for webpack -->
<% if (false) { %><scriptsrc="src/index.ts"></script><% } %>
</body></html>html
/* shared styles are loaded from: *//* https://static.infragistics.com/xplatform/css/samples */css
Like this sample? Get access to our complete Ignite UI for Web Components toolkit and start building your own apps in minutes. Download it for free.
Web Components Chart with High-Volume
대용량 시나리오에서 Web Components 차트는 100만 개의 데이터 요소를 렌더링할 수 있으며 최종 사용자가 확대/축소하거나 차트 콘텐츠를 탐색하려고 할 때 차트가 원활한 성능을 계속 제공합니다. 다음 샘플에서는 대량 시나리오를 보여 줍니다 IgcCategoryChartComponent.
EXAMPLE
DATA
TS
HTML
CSS
exportclassCategoryChartSharedData{
publicstatic generateItems(startValue: number, maxPoints: number, useShortLabels?: boolean): any[] {
const data: any[] = [];
let value = startValue;
for (let i = 0; i <= maxPoints; i++) {
value += Math.random() * 4.0 - 2.0;
const v = Math.round(value);
let l = i.toString();
if (useShortLabels) {
l = this.toShortString(i);
}
data.push({ Label: l, Value: v });
}
return data;
}
publicstatic getTemperatures(startValue: number, startYear: number, endYear: number): any[] {
const data: any[] = [];
let value = startValue;
for (let i = startYear; i <= endYear; i++) {
value += (Math.random() - 0.5) * 0.5;
const v = Math.abs(Math.round(value * 10) / 10);
data.push({ Label: i.toString(), Value: v });
}
return data;
}
publicstatic getLastItem(array: any[]): any {
if (array.length === 0) {
returnnull;
}
return array[array.length - 1];
}
publicstatic getNewItem(array: any[], index: number): any {
const lastItem = this.getLastItem(array);
const newValue = lastItem.Value + Math.random() * 4.0 - 2.0;
return { Label: index.toString(), Value: newValue };
}
publicstatic toShortString(largeValue: number): string {
let roundValue: number;
if (largeValue >= 1000000) {
roundValue = Math.round(largeValue / 100000) / 10;
return roundValue + "m";
}
if (largeValue >= 1000) {
roundValue = Math.round(largeValue / 100) / 10;
return roundValue + "k";
}
roundValue = Math.round(largeValue);
return roundValue + "";
}
publicstatic addDays(date: Date, days: number): Date {
date.setDate(date.getDate() + days);
return date;
}
}
ts
import { IgcCategoryChartModule } from'igniteui-webcomponents-charts';
import { IgcCategoryChartComponent } from'igniteui-webcomponents-charts';
import { ModuleManager } from'igniteui-webcomponents-core';
import { CategoryChartSharedData } from'./CategoryChartSharedData';
ModuleManager.register(IgcCategoryChartModule);
exportclassCategoryChartHighVolume{
private chart: IgcCategoryChartComponent;
public dataPoints: number = 500000;
public dataInfo: string = CategoryChartSharedData.toShortString(this.dataPoints);
public data: any[] = [];
private dataInfoLabel: HTMLLabelElement;
constructor() {
this.onDataPointsChanged = this.onDataPointsChanged.bind(this);
this.onDataGenerateClick = this.onDataGenerateClick.bind(this);
this.chart = document.getElementById('chart') as IgcCategoryChartComponent;
this.chart.dataSource = CategoryChartSharedData.generateItems(0, this.dataPoints, true);
let slider1 = document.getElementById('dataPointsSlider') as HTMLInputElement;
slider1!.addEventListener('change', this.onDataPointsChanged);
let DataGenerate1 = document.getElementById('DataGenerate') as HTMLButtonElement;
DataGenerate1!.addEventListener('click', this.onDataGenerateClick);
}
public onDataPointsChanged = (e: any) => {
this.dataPoints = e.target.value;
const info = CategoryChartSharedData.toShortString(this.dataPoints);
this.dataPoints = this.dataPoints;
this.dataInfo = info;
this.dataInfoLabel = document.getElementById('dataInfoLabel') as HTMLLabelElement;
this.dataInfoLabel.textContent = this.dataPoints.toString();
}
public onDataGenerateClick = (e: any) => {
if (this.dataPoints === undefined) {
this.dataPoints = 10000;
}
this.generateData();
}
publicgenerateData() {
this.chart.dataSource = CategoryChartSharedData.generateItems(0, this.dataPoints, true);
}
}
new CategoryChartHighVolume();
ts
<!DOCTYPE html><html><head><title>CategoryChartHighVolume</title><metacharset="UTF-8" /><linkrel="shortcut icon"href="https://static.infragistics.com/xplatform/images/browsers/wc.png" ><linkrel="stylesheet"href="https://fonts.googleapis.com/icon?family=Material+Icons" /><linkrel="stylesheet"href="https://fonts.googleapis.com/css?family=Kanit&display=swap" /><linkrel="stylesheet"href="https://fonts.googleapis.com/css?family=Titillium Web" /><linkrel="stylesheet"href="https://static.infragistics.com/xplatform/css/samples/shared.v8.css"type="text/css" /></head><body><divid="root"><divclass="container sample"><divclass="options horizontal"><labelclass="options-label">Data Points: </label><labelclass="options-value"id="dataInfoLabel"> 500000 </label><inputid="dataPointsSlider"class="options-slider"type="range"min="10000"max="1000000"step="1000"value=500000 /><buttonid="DataGenerate">Generate Data</button></div><igc-category-chartid="chart"width="100%"height="calc(100% - 3rem)"chart-type="Line"tool-tip-type="Default"y-axis-extent="60"x-axis-enhanced-interval-prefer-more-category-labels="false"should-consider-auto-rotation-for-initial-labels="false"should-auto-expand-margin-for-initial-labels="false"crosshairs-display-mode="None"auto-margin-and-angle-update-mode="None"marker-types="None" ></igc-category-chart></div></div><!-- This script is needed only for parcel and it will be excluded for webpack -->
<% if (false) { %><scriptsrc="src/index.ts"></script><% } %>
</body></html>html
/* shared styles are loaded from: *//* https://static.infragistics.com/xplatform/css/samples */css
General Performance Guidelines
이 섹션에서는 Web Components 차트에서 오버헤드와 처리 업데이트를 추가하는 지침과 차트 기능을 나열합니다.
Data Size
많은 수의 데이터 포인트(예: 10,000+)가 있는 데이터 소스를 플로팅해야 하는 경우 해당 목적을 위해 특별히 설계된 다음 유형의 시리즈 중 하나와 함께 Web Components IgcDataChartComponent를 사용하는 것이 좋습니다.
Web Components 차트는 데이터 포인트 배열의 배열을 속성에 바인딩하여 여러 데이터 소스의 렌더링을 ItemsSource 지원합니다. 여러 데이터 소스가 각 데이터 소스에 하나의 데이터 열만 포함되는 단일 데이터 소스로 평면화되는 경우 차트의 경우 훨씬 더 빠릅니다. 예를 들어:
Web Components 차트에 범례를 추가하면 범례에 매핑된 계열 또는 데이터 항목의 제목이 런타임에 자주 변경되는 경우 성능이 저하될 수 있습니다.
차트 마커
Web Components 차트에서 마커는 차트의 레이아웃 복잡성을 추가하고 특정 정보를 얻기 위해 데이터 바인딩을 수행하기 때문에 차트 성능과 관련하여 특히 비쌉니다. 또한 마커는 데이터 포인트가 많거나 바인딩된 데이터 소스가 많은 경우 성능을 저하시킵니다. 따라서 마커가 필요하지 않은 경우 차트에서 제거해야 합니다.
이 코드 스니펫은 Web Components 차트에서 마커를 제거하는 방법을 보여줍니다.
// on CategoryChart or FinancialChartthis.Chart.markerTypes.clear();
this.Chart.markerTypes.add(MarkerType.None);
// on LineSeries of DataChartthis.LineSeries.markerType = MarkerType.None;
ts
Chart Resolution
resolution 속성을 더 높은 값으로 설정하면 성능이 향상되지만 플롯된 계열 선의 그래픽 충실도가 낮아집니다. 따라서 충실도가 허용되지 않을 때까지 늘릴 수 있습니다.
이 코드 조각은 Web Components 차트에서 해상도를 낮추는 방법을 보여줍니다.
// on CategoryChart or FinancialChart:this.Chart.Resolution = 10;
// on LineSeries of DataChart:this.LineSeries.Resolution = 10;
ts
데이터 포인트 사이의 시간 범위를 기준으로 데이터 포인트 사이의 공백이 중요하지 않은 경우 DateTime 지원과 함께 x축을 사용하지 않는 것이 좋습니다. 대신, 데이터를 통합하는 방식이 더 효율적이기 때문에 순서/범주 축을 사용해야 합니다. 또한 순서/범주 축은 시간 기반 X축처럼 데이터에 대한 정렬을 수행하지 않습니다.
The IgcCategoryChartComponent already uses ordinal/category axis so there is no need to change its properties.
기본적으로 Web Components 차트는 데이터 범위에 따라 자동으로 계산 yAxisInterval 됩니다. 따라서 너무 많은 축 눈금선과 축 레이블이 렌더링되지 않도록 하기 위해 축 간격을 특히 작은 값으로 설정하지 않아야 합니다. 또한 많은 축 눈금선이나 축 레이블이 필요하지 않은 경우 자동으로 계산되는 축 간격보다 큰 값으로 속성을 늘리는 yAxisInterval 것을 고려할 수 있습니다.
We do not recommend setting axis minor interval as it will decrease chart performance.
이 코드 조각은 Web Components 차트에서 축 주 간격을 설정하는 방법을 보여줍니다.
그러나 Web Components 차트는 true로 설정된 경우 yAxisAbbreviateLargeNumbers 축 레이블에 표시되는 큰 숫자(예: 10,000+)의 약어를 지원합니다. 대신 데이터 항목의 큰 값을 공통 계수로 나누어 사전 처리한 다음 데이터 값을 축약하는 데 사용되는 계수를 나타내는 문자열로 설정하는 yAxisTitle 것이 좋습니다.
이 코드 조각은 Web Components 차트에서 축 제목을 설정하는 방법을 보여줍니다.
<igc-category-charty-axis-title="In millions of Dollars"></igc-category-chart><igc-financial-charty-axis-title="In millions of Dollars"></igc-financial-chart><igc-data-chart><igc-numeric-y-axistitle="In millions of Dollars"></igc-numeric-y-axis></igc-data-chart>html
Axis Labels Extent
런타임에 Web Components 차트는 가장 긴 값을 가진 레이블을 기준으로 y축에서 레이블의 범위를 조정합니다. 이로 인해 데이터 범위가 변경되고 레이블을 자주 업데이트해야 하는 경우 차트 성능이 저하될 수 있습니다. 따라서 차트 성능을 향상시키기 위해 디자인 타임에 레이블 범위를 설정하는 것이 좋습니다.
다음 코드 스니펫은 Web Components 차트에서 y축의 레이블에 대한 고정 범위를 설정하는 방법을 보여줍니다.
또한 많은 시리즈를 추가하면 IgcSeriesComponent Web Components의 수집 IgcDataChartComponent 컨트롤은 각 시리즈에 자체 렌더링 캔버스가 있기 때문에 렌더링에 오버헤드를 추가합니다. 이는 데이터 차트에 10개 이상의 시리즈가 있는 경우 특히 중요합니다. 여러 데이터 소스를 평면화된 데이터 소스로 결합하는 것이 좋습니다(데이터 구조 섹션) 그런 다음 다음 시리즈의 조건부 스타일 기능을 사용합니다.