JavaScript로 더 명확한 Excel 차트: 다중 레벨 레이블과 이중 축

지역과 월을 같은 축에 놓은 세로 막대형 차트에는 두 가지 문제가 있으며, 이 둘은 같은 문제가 아닙니다. 첫 번째는 범주 레이블이 단일 행 — "북부", "1월", "북부", "2월" — 으로 합쳐져서, 읽는 사람이 어느 월이 어느 지역에 속하는지 머릿속으로 다시 묶어야 한다는 점입니다. 두 번째는 매출 계열이 수백만 단위에 달하는데 성장률 계열을 함께 추가하면, 하나의 값 축이 두 가지 규모를 동시에 처리할 수 없기 때문에 성장률이 기준선에 붙은 평평한 선이 된다는 점입니다.
다중 수준 범주 레이블은 첫 번째 문제를 해결합니다. 보조 축은 두 번째 문제를 해결합니다. 이 둘은 같은 차트에서 유용하게 쓰일 뿐 서로 독립적인 기능이며, Spire.XLS for JavaScript는 차트 축 API를 통해 두 가지를 모두 처리합니다. 즉, 백엔드 없이 가상 파일 시스템(VFS)을 통해 파일을 이동하면서 브라우저의 WebAssembly에서 직접 실행됩니다.
프로젝트 설정은 React 프로젝트에 Spire.XLS for JavaScript 통합하기를 참조하세요. 아래 예제는 패키지가 설치되어 있고 WebAssembly 모듈이 초기화되었다고 가정합니다.
하나의 축으로 충분하지 않을 때
두 문제는 같은 종류의 워크시트 — 범주에 계층이 있고 값의 범위가 넓은 워크시트 — 에서 나타나지만, 원인은 서로 다릅니다:
| 문제 | 원인 | 차트 모양 | 해결 방법 |
|---|---|---|---|
| 레이블이 한 행에 몰림 | 범주가 계층적임(지역 → 월, 연도 → 분기)이지만 축은 이를 평면적으로 처리함 | 외부 및 내부 범주가 시각적 그룹화 없이 번갈아 나타나는 단일 레이블 행 | 다중 수준 범주 레이블 |
| 한 계열이 선으로 평평해짐 | 두 계열이 규모 차이가 큼(매출은 백만 단위, 성장률은 퍼센트)이지만 하나의 값 축을 공유함 | 더 작은 계열이 거의 0에 가깝게 압축되어 변동이 보이지 않음 | 보조 축 |
둘 다 스타일 문제가 아닙니다. 둘 모두 축이 알아야 할 무언가를 모르기 때문에 발생합니다. 즉, 범주에 계층이 있다는 것, 또는 값의 눈금이 서로 호환되지 않는다는 것입니다. 아래 두 섹션에서 이를 차례로 다루며, 두 번째 섹션은 첫 번째를 기반으로 하여 최종 차트가 두 가지 해결책을 모두 갖추도록 합니다.
사전 요구 사항
Spire.XLS for JavaScript가 설치되고 WebAssembly 모듈이 초기화된 React 프로젝트가 필요하며, 모듈은 window.wasmModule.spirexls에서 접근할 수 있어야 합니다. 샘플은 차트를 만들기 전에 글꼴과 미리 준비된 데이터 파일을 VFS에 로드하며, 둘 다 프로젝트의 public 폴더에서 가져옵니다.
다중 수준 레이블 뒤의 데이터
다중 수준 레이블은 속성 하나만으로 만들어지지 않습니다. 데이터에서 읽어옵니다. 범주 축은 CategoryLabels가 가리키는 범위에 있는 열 수만큼 레이블 수준을 그립니다. 따라서 워크시트는 계층이 열을 가로질러 배치되도록 구성해야 합니다:
| 열 A(외부) | 열 B(내부) | 열 C(값) |
|---|---|---|
| 북부 | 1월 | 120,000 |
| 북부 | 2월 | 135,000 |
| 남부 | 1월 | 98,000 |
| 남부 | 2월 | 110,000 |
열 A의 외부 레이블은 해당 레이블이 포괄하는 행에 걸쳐 병합됩니다. "북부"는 1월과 2월의 두 행에 걸쳐 있습니다. 이 병합 덕분에 차트가 렌더링될 때 해당 수준이 그룹당 단일 레이블로 시각적으로 합쳐집니다. 병합하지 않으면 축은 여전히 두 수준을 표시하지만, 외부 수준이 그룹화되지 않고 각 행마다 레이블을 반복합니다.
이것은 차트 API의 문제가 아니라 데이터 배치의 문제입니다. 차트 코드는 CategoryLabels가 두 열을 모두 가리키도록 하기만 하면 됩니다. 외부 셀이 병합되는지 여부는 차트 개체가 아니라 통합 문서에서 결정됩니다.
다중 수준 범주 레이블이 있는 차트 만들기
데이터가 배치되면 차트 코드는 두 가지를 수행합니다. CategoryLabels가 외부 열과 내부 열을 모두 포괄하는 범위를 가리키게 하고, MultiLevelLable을 켜서 축이 해당 열을 누적된 행으로 확장하도록 합니다. 단계는 다음과 같습니다:
- 글꼴과 테스트 데이터 파일을 VFS에 로드합니다.
- 통합 문서를 로드하고 워크시트를 가져옵니다.
- 세로 막대형 차트를 추가하고 이름이 지정된 매출 계열을 추가합니다.
- 범주 레이블이 지역과 월 열을 모두 가리키도록 합니다.
- 범주 축에 대해 다중 수준 레이블을 켜고 통합 문서를 저장합니다.
function App() {
const createMultiLevelChart = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales";
chart.Legend.Delete();
// Add the sales series and give it a name
const serie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
serie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
serie.CategoryLabels = sheet.Range.get("A2:B7");
// Turn on multi-level category labels so each level gets its own row
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "MultiLevelLabels.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Multi-Level Labels</h1>
<button onClick={createMultiLevelChart}>Start</button>
</div>
);
}
export default App;
각 수준이 자체 행에 표시되는 다중 수준 범주 레이블이 있는 차트

축이 두 수준을 표시하도록 하는 것은 A2:B7 범위입니다. B2:B7과 같은 단일 열 범위를 바인딩하면 MultiLevelLable이 true로 설정되어 있어도 여전히 하나의 수준만 생성됩니다. 이 속성은 여러 수준을 행으로 확장할지 여부를 제어할 뿐, 확장할 데이터 수준이 존재하는지 여부를 제어하지 않습니다.
성장 계열이 사라지는 이유
전년 대비 성장률에 대한 두 번째 계열 — 10%대 초반의 백분율 값 — 을 추가하고 매출과 같은 값 축에 표시해 보겠습니다. 매출 막대는 120,000에 도달하지만 성장률은 12에 도달합니다. 0에서 140,000까지 눈금이 매겨진 축에서는 숫자 12가 0과 구별되지 않습니다. 계열은 존재하고 데이터도 정확하지만, 차트에는 기준선에 붙은 평평한 선이 표시됩니다.
이것은 데이터나 차트의 버그가 아닙니다. 가장 큰 계열을 포괄하는 범위를 매핑하는 값 축이 제 역할을 하는 대신, 가장 작은 계열을 희생한 결과입니다. 두 계열을 모두 선명하게 보려면 각각 고유한 눈금을 부여해야 하며, 보조 축이 바로 그 역할을 합니다.
계열을 보조 축으로 이동
성장 계열은 막대가 아니라 선으로 추가합니다. 선은 막대 너비를 차지하지 않으므로, 같은 범주를 공유하는 막대 계열과 대비되어 선명하게 보입니다. 이를 기본 축에서 분리하는 방법은 속성 하나입니다: UsePrimaryAxis = false. 단계는 다음과 같습니다:
- 글꼴과 테스트 데이터 파일을 VFS에 로드합니다.
- 통합 문서를 로드하고 워크시트를 가져옵니다.
- 세로 막대형 차트를 추가하고 이름이 지정된 매출 계열을 추가합니다.
- 성장 계열을 선으로 추가합니다.
- 성장 계열을 보조 축으로 이동하고 통합 문서를 저장합니다.
function App() {
const addSecondaryAxis = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales and YoY Growth";
// Add the sales series, which stays on the primary axis
const salesSerie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
salesSerie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
salesSerie.CategoryLabels = sheet.Range.get("A2:B7");
// Add the growth series as a line
const growthSerie = chart.Series.Add({ name: "YoY Growth", serieType: xlsModule.ExcelChartType.Line });
growthSerie.Values = sheet.Range.get("D2:D7");
// Move the growth series to the secondary axis so it plots on its own percentage scale
growthSerie.UsePrimaryAxis = false;
// Turn on multi-level category labels
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "SecondaryAxis.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Secondary Axis</h1>
<button onClick={addSecondaryAxis}>Start</button>
</div>
);
}
export default App;
성장률 선 계열을 위한 보조 축이 있는 세로 막대형 차트

UsePrimaryAxis = false는 설정된 계열에만 영향을 미치며, 다른 모든 계열은 기본 축에 남습니다. 차트에는 두 번째 값 축과 범주 축 쌍이 생겨 두 개의 별도 눈금 범위를 갖게 됩니다. Series.Add는 계열 이름을 동시에 받으므로, 범례에는 자동 생성된 "Series 1" 대신 전달한 이름이 표시됩니다.
보조 축 눈금 설정
계열이 보조 축으로 이동하면 해당 축은 자체적으로 눈금을 계산하며, 기본 축과 독립적으로 계산합니다. 두 범위는 서로를 알지 못하므로 보조 축이 데이터와 잘 맞지 않는 범위를 선택할 수 있습니다.
PrimaryValueAxis.MinValue, MaxValue, MajorUnit은 기본 축만 제어합니다. 보조 축 눈금을 설정하려면 SecondaryValueAxis를 사용하세요:
// Give the secondary axis a 0-20 scale with a major unit of 5
chart.SecondaryValueAxis.MinValue = 0;
chart.SecondaryValueAxis.MaxValue = 20;
chart.SecondaryValueAxis.MajorUnit = 5;
눈금은 계열을 보조 축으로 이동한 후에 설정하세요. 보조 축을 사용하는 계열이 없으면 할당은 받아들여지지만 파일에 기록되지 않습니다. 즉, 계열이 그 위에 그려지기 전까지 출력에 해당 축은 존재하지 않습니다.
일반적인 문제
범주 축에 한 수준의 레이블만 표시됩니다.
CategoryLabels가 단일 열 범위를 가리키고 있습니다. 수준 수는 범위가 포괄하는 열 수에 따라 결정되며, MultiLevelLable 속성에 따라 결정되지 않습니다. A2:B7과 같은 여러 열 범위를 가리키고, 데이터에서 외부 레이블 셀이 병합되었는지 확인하세요.
보조 축 눈금이 잘못된 것처럼 보입니다.
기본 및 보조 값 축은 각각 독립적으로 눈금을 계산합니다. PrimaryValueAxis에 MinValue 또는 MaxValue를 설정해도 보조 축에는 영향을 주지 않습니다. chart.SecondaryValueAxis를 사용하여 해당 눈금을 직접 설정하고, 계열을 그 축으로 이동한 후에 설정하세요.
보조 축을 추가한 후에도 성장 계열이 여전히 평평하게 나타납니다.
UsePrimaryAxis = false가 매출 계열이 아니라 성장 계열에 설정되어 있는지 확인하세요. 이 속성은 계열별로 적용되므로, 잘못된 계열에 설정하면 잘못된 계열이 보조 축으로 이동합니다.
범례에 계열 이름 대신 "Series 1"이 표시됩니다.
이름이 Series.Add에 전달되지 않았습니다. chart.Series.Add({ name: "Sales", ... })를 사용하여 범례가 자동 생성 레이블이 아니라 의도한 이름을 가져오도록 하세요.
자주 묻는 질문
범주 레이블을 두 수준 이상으로 가질 수 있나요?
예. 수준 수는 CategoryLabels 범위가 포괄하는 열 수에 따라 결정됩니다. 3열 범위는 세 수준을 생성합니다. 예를 들어 연도, 분기, 월입니다. 각 수준이 올바르게 그룹화되려면 데이터에서 외부 레이블 셀이 병합되어야 합니다.
보조 축이 세로 막대형 및 선형 외의 차트 종류에서도 작동하나요?
예. 보조 축은 특정 차트 종류에 묶여 있지 않습니다. 일반적인 패턴은 세로 막대형과 선의 조합입니다. 선은 막대 너비를 차지하지 않아 막대와 대비되어 선명하게 보입니다. 하지만 UsePrimaryAxis = false를 설정하면 모든 계열을 보조 축으로 이동할 수 있습니다.
이 차트를 만들려면 Excel이 설치되어 있어야 하나요?
아니요. 스프레드시트 엔진은 패키지에 포함되어 제공되며 브라우저에서 WebAssembly로 실행됩니다. 통합 문서는 전적으로 클라이언트 측에서 작성, 차트 생성, 저장됩니다.
보조 범주 축을 별도로 제어할 수 있나요?
계열이 보조 축으로 이동하면 차트에는 보조 값 축 외에도 보조 범주 축이 생깁니다. 두 범주 축은 기본적으로 동일한 범주 레이블을 공유하므로 다중 수준 레이블이 둘 다에 적용됩니다.
출력 파일이 Excel과 호환되나요?
예. 통합 문서는 .xlsx로 저장되며, 다중 수준 레이블과 보조 축을 포함한 차트는 Excel이 기본적으로 읽는 표준 차트 XML로 작성됩니다.
참고 항목
Grafici Excel più chiari in JavaScript: etichette multilivello e doppi assi
Indice dei contenuti

Un grafico a colonne con regioni e mesi sullo stesso asse presenta due problemi, e non si tratta dello stesso problema. Il primo è che le etichette di categoria si riducono a un'unica riga — "North", "Jan", "North", "Feb" — e il lettore deve raggruppare mentalmente quale mese appartiene a quale regione. Il secondo è che quando una serie di tasso di crescita viene aggiunta accanto a una serie di vendite che arriva a milioni, il tasso di crescita diventa una linea piatta aderente alla linea di base, perché un unico asse dei valori non può servire due ordini di grandezza contemporaneamente.
Le etichette di categoria multilivello risolvono il primo problema. Un asse secondario risolve il secondo. Sono funzionalità indipendenti che si trovano a essere utili sullo stesso grafico, e Spire.XLS for JavaScript gestisce entrambe tramite l'API degli assi del grafico — direttamente nel browser su WebAssembly, con i file che transitano attraverso un file system virtuale (VFS) e senza alcun backend coinvolto.
Per la configurazione del progetto, vedere Integrare Spire.XLS for JavaScript in un progetto React. Gli esempi seguenti presuppongono che il pacchetto sia installato e che il modulo WebAssembly sia stato inizializzato.
Quando un asse non è sufficiente
I due problemi si presentano sullo stesso tipo di foglio di lavoro — uno in cui le categorie hanno una gerarchia e i valori hanno un'ampia gamma — ma provengono da origini diverse:
| Problema | Da dove deriva | Come appare il grafico | Cosa lo risolve |
|---|---|---|---|
| Le etichette si accalcano in un'unica riga | Le categorie sono gerarchiche (regione → mese, anno → trimestre) ma l'asse le tratta come piatte | Un'unica riga di etichette in cui le categorie esterne e interne si alternano senza raggruppamento visivo | Etichette di categoria multilivello |
| Una serie si appiattisce in una linea | Due serie differiscono di ordini di grandezza (vendite in milioni, crescita in percentuale) ma condividono un unico asse dei valori | La serie più piccola si comprime quasi a zero e la sua variazione è invisibile | Asse secondario |
Nessuno dei due è un problema di stile. Entrambi dipendono dal fatto che l'asse non sa qualcosa che deve sapere — che le categorie hanno livelli, o che i valori hanno scale incompatibili. Le due sezioni seguenti li affrontano una dopo l'altra, e la seconda si basa sulla prima, così il grafico finale contiene entrambe le soluzioni.
Prerequisiti
Serve un progetto React con Spire.XLS for JavaScript installato e il modulo WebAssembly inizializzato, accessibile all'indirizzo window.wasmModule.spirexls. L'esempio carica un font e un file di dati predefinito nella VFS prima di creare il grafico, ed entrambi vengono recuperati dalla cartella public del progetto.
I dati alla base delle etichette multilivello
Le etichette multilivello non vengono create da una sola proprietà — vengono lette dai dati. L'asse delle categorie disegna tanti livelli di etichette quante sono le colonne nell'intervallo a cui punta CategoryLabels. Quindi il foglio di lavoro deve essere organizzato con la gerarchia distribuita sulle colonne:
| Colonna A (esterna) | Colonna B (interna) | Colonna C (valori) |
|---|---|---|
| North | Jan | 120,000 |
| North | Feb | 135,000 |
| South | Jan | 98,000 |
| South | Feb | 110,000 |
Le etichette esterne nella colonna A sono unite per tutte le righe che coprono — "North" comprende le due righe di Jan e Feb. È questa unione che fa sì che il livello si comprima visivamente in un'unica etichetta per gruppo quando il grafico viene renderizzato. Senza di essa, l'asse mostra comunque due livelli, ma il livello esterno ripete l'etichetta su ogni riga invece di raggrupparla.
Questa è una questione di layout dei dati, non di API del grafico. Il codice del grafico deve solo far puntare CategoryLabels a entrambe le colonne; se le celle esterne sono unite viene deciso nella cartella di lavoro, non nell'oggetto grafico.
Creare un grafico con etichette di categoria multilivello
Una volta organizzati i dati, il codice del grafico fa due cose: fa puntare CategoryLabels a un intervallo che comprende sia la colonna esterna sia quella interna, e attiva MultiLevelLable in modo che l'asse espanda tali colonne in righe sovrapposte. I passaggi sono:
- Caricare il font e il file di dati di test nella VFS.
- Caricare la cartella di lavoro e ottenere il foglio di lavoro.
- Aggiungere un grafico a colonne e aggiungere una serie di vendite con nome.
- Far puntare le etichette di categoria sia alla colonna della regione sia a quella del mese.
- Attivare le etichette multilivello per l'asse delle categorie e salvare la cartella di lavoro.
function App() {
const createMultiLevelChart = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales";
chart.Legend.Delete();
// Add the sales series and give it a name
const serie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
serie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
serie.CategoryLabels = sheet.Range.get("A2:B7");
// Turn on multi-level category labels so each level gets its own row
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "MultiLevelLabels.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Multi-Level Labels</h1>
<button onClick={createMultiLevelChart}>Start</button>
</div>
);
}
export default App;
Un grafico con etichette di categoria multilivello, ogni livello sulla propria riga

È l'intervallo A2:B7 che fa mostrare all'asse due livelli. Associare un intervallo a colonna singola come B2:B7 produrrebbe comunque un solo livello anche con MultiLevelLable impostato su true — la proprietà controlla se più livelli vengono espansi in righe, non se esiste un livello di dati da espandere.
Perché la serie di crescita scompare
Aggiungete una seconda serie per la crescita anno su anno — valori a due cifre basse, percentuali — e tracciatela sullo stesso asse dei valori delle vendite. Le colonne delle vendite raggiungono 120,000; il tasso di crescita raggiunge 12. Su un asse che va da 0 a 140,000, il numero 12 è indistinguibile dallo zero. La serie c'è, i dati sono corretti, e il grafico mostra una linea piatta contro la linea di base.
Non è un bug nei dati o nel grafico. È l'asse dei valori che fa il suo lavoro — mappare un intervallo che copre la serie più grande — a scapito della più piccola. L'unico modo per vedere chiaramente entrambe le serie è dare a ciascuna la propria scala, ed è ciò che fa l'asse secondario.
Spostare una serie sull'asse secondario
La serie di crescita viene aggiunta come linea anziché come colonna. Una linea non occupa larghezza di barra, quindi risulta ben leggibile rispetto alla serie a colonne che condivide le stesse categorie. Spostarla dall'asse primario richiede una sola proprietà: UsePrimaryAxis = false. I passaggi sono:
- Caricare il font e il file di dati di test nella VFS.
- Caricare la cartella di lavoro e ottenere il foglio di lavoro.
- Aggiungere un grafico a colonne e aggiungere una serie di vendite con nome.
- Aggiungere la serie di crescita come linea.
- Spostare la serie di crescita sull'asse secondario e salvare la cartella di lavoro.
function App() {
const addSecondaryAxis = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales and YoY Growth";
// Add the sales series, which stays on the primary axis
const salesSerie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
salesSerie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
salesSerie.CategoryLabels = sheet.Range.get("A2:B7");
// Add the growth series as a line
const growthSerie = chart.Series.Add({ name: "YoY Growth", serieType: xlsModule.ExcelChartType.Line });
growthSerie.Values = sheet.Range.get("D2:D7");
// Move the growth series to the secondary axis so it plots on its own percentage scale
growthSerie.UsePrimaryAxis = false;
// Turn on multi-level category labels
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "SecondaryAxis.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Secondary Axis</h1>
<button onClick={addSecondaryAxis}>Start</button>
</div>
);
}
export default App;
Un grafico a colonne con un asse secondario per la serie a linee del tasso di crescita

UsePrimaryAxis = false influisce solo sulla serie su cui è impostato; tutte le altre serie rimangono sull'asse primario. Il grafico acquisisce una seconda coppia di assi dei valori e delle categorie, ottenendo due intervalli di scala separati. Series.Add accetta contemporaneamente il nome della serie, così la legenda mostra il nome passato invece di un "Series 1" generato automaticamente.
Impostare la scala dell'asse secondario
Una volta che una serie passa all'asse secondario, quell'asse calcola la propria scala — e lo fa indipendentemente da quello primario. I due intervalli non si conoscono a vicenda, il che significa che l'asse secondario potrebbe scegliere limiti che non si allineano bene con i dati.
PrimaryValueAxis.MinValue, MaxValue e MajorUnit controllano solo l'asse primario. Per impostare la scala dell'asse secondario, usate SecondaryValueAxis:
// Give the secondary axis a 0-20 scale with a major unit of 5
chart.SecondaryValueAxis.MinValue = 0;
chart.SecondaryValueAxis.MaxValue = 20;
chart.SecondaryValueAxis.MajorUnit = 5;
Impostate la scala dopo che la serie è stata spostata sull'asse secondario. Finché nessuna serie utilizza l'asse secondario, l'assegnazione viene accettata ma non viene mai scritta nel file — l'asse non esiste nell'output finché non vi viene tracciata una serie.
Problemi comuni
L'asse delle categorie mostra un solo livello di etichette.
CategoryLabels punta a un intervallo a colonna singola. Il numero di livelli è determinato da quante colonne copre l'intervallo, non dalla proprietà MultiLevelLable. Puntate a un intervallo multicolonna come A2:B7 e assicuratevi che le celle delle etichette esterne siano unite nei dati.
La scala dell'asse secondario sembra sbagliata.
Gli assi dei valori primario e secondario calcolano le rispettive scale in modo indipendente. Impostare MinValue o MaxValue su PrimaryValueAxis non influisce sull'asse secondario. Usate chart.SecondaryValueAxis per impostarne direttamente la scala, e fatelo dopo aver spostato una serie su di esso.
La serie di crescita appare ancora piatta dopo aver aggiunto un asse secondario.
Verificate che UsePrimaryAxis = false sia impostato sulla serie di crescita, non su quella delle vendite. La proprietà è per serie — impostarla sulla serie sbagliata sposta quella sbagliata sull'asse secondario.
La legenda mostra "Series 1" invece del nome della serie.
Il nome non è stato passato a Series.Add. Usate chart.Series.Add({ name: "Sales", ... }) in modo che la legenda riprenda il nome che intendevate invece di un'etichetta generata automaticamente.
FAQ
Posso avere più di due livelli di etichette di categoria?
Sì. Il numero di livelli è determinato dal numero di colonne che l'intervallo CategoryLabels copre. Un intervallo a tre colonne produce tre livelli — ad esempio anno, trimestre e mese. Le celle delle etichette esterne devono essere unite nei dati affinché ogni livello venga raggruppato correttamente.
L'asse secondario funziona con tipi di grafico diversi da colonne e linee?
Sì. L'asse secondario non è legato a un tipo di grafico specifico. Lo schema più comune è colonne più linee — la linea non occupa larghezza di barra e risulta ben leggibile rispetto alle colonne — ma qualsiasi serie può essere spostata sull'asse secondario impostando UsePrimaryAxis = false.
Devo avere Excel installato per creare questi grafici?
No. Il motore per fogli di calcolo è incluso nel pacchetto e viene eseguito come WebAssembly nel browser. La cartella di lavoro viene creata, rappresentata con grafici e salvata interamente lato client.
Posso controllare separatamente l'asse delle categorie secondario?
Quando una serie passa all'asse secondario, il grafico acquisisce un asse delle categorie secondario oltre all'asse dei valori secondario. I due assi delle categorie condividono le stesse etichette di categoria per impostazione predefinita, quindi le etichette multilivello si applicano a entrambi.
Il file di output è compatibile con Excel?
Sì. La cartella di lavoro viene salvata come .xlsx e il grafico — comprese le etichette multilivello e l'asse secondario — viene scritto come XML di grafico standard che Excel legge nativamente.
Vedi anche
Graphiques Excel plus clairs en JavaScript : étiquettes à plusieurs niveaux et double axe
Table des matières
- Quand un seul axe ne suffit pas
- Prérequis
- Les données derrière les étiquettes multi-niveaux
- Créer un graphique avec des étiquettes de catégorie multi-niveaux
- Pourquoi la série de croissance disparaît
- Déplacer une série vers l'axe secondaire
- Définir l'échelle de l'axe secondaire
- Problèmes courants
- FAQ
- Voir aussi

Un graphique à colonnes comportant des régions et des mois sur un même axe pose deux problèmes, et ce ne sont pas les mêmes problèmes. Le premier est que les étiquettes de catégorie se réduisent à une seule ligne — « Nord », « Janv. », « Nord », « Févr. » — et le lecteur doit regrouper mentalement quel mois appartient à quelle région. Le second est que, lorsqu'une série de taux de croissance est ajoutée à côté d'une série de ventes qui se chiffre en millions, le taux de croissance devient une ligne plate collée à la ligne de base, car un seul axe des valeurs ne peut pas servir deux ordres de grandeur à la fois.
Les étiquettes de catégorie multi-niveaux corrigent le premier. Un axe secondaire corrige le second. Ce sont des fonctionnalités indépendantes qui se trouvent être utiles sur le même graphique, et Spire.XLS for JavaScript gère les deux via l'API d'axe du graphique — directement dans le navigateur sous WebAssembly, les fichiers transitant par un système de fichiers virtuel (VFS) et sans aucun backend.
Pour la configuration du projet, consultez Intégrer Spire.XLS for JavaScript dans un projet React. Les exemples ci-dessous supposent que le package est installé et que le module WebAssembly a été initialisé.
Quand un seul axe ne suffit pas
Les deux problèmes apparaissent sur le même type de feuille de calcul — une feuille où les catégories présentent une hiérarchie et où les valeurs s'étalent largement — mais ils proviennent d'endroits différents :
| Problème | Son origine | À quoi ressemble le graphique | Ce qui le corrige |
|---|---|---|---|
| Les étiquettes s'empilent sur une seule ligne | Les catégories sont hiérarchiques (région → mois, année → trimestre) mais l'axe les traite comme plates | Une seule ligne d'étiquettes où les catégories externes et internes alternent sans regroupement visuel | Étiquettes de catégorie multi-niveaux |
| Une série s'aplatit en une ligne | Deux séries diffèrent de plusieurs ordres de grandeur (ventes en millions, croissance en pourcentage) mais partagent un seul axe des valeurs | La plus petite série se comprime vers zéro et sa variation est invisible | Axe secondaire |
Aucun des deux n'est un problème de style. Dans les deux cas, l'axe ignore quelque chose qu'il doit savoir — que les catégories comportent des niveaux, ou que les valeurs ont des échelles incompatibles. Les deux sections ci-dessous les traitent tour à tour, et la seconde s'appuie sur la première afin que le graphique final intègre les deux corrections.
Prérequis
Vous avez besoin d'un projet React avec Spire.XLS for JavaScript installé et le module WebAssembly initialisé, accessible via window.wasmModule.spirexls. L'exemple charge une police et un fichier de données prédéfini dans le VFS avant de créer le graphique, et les deux sont récupérés depuis le dossier public du projet.
Les données derrière les étiquettes multi-niveaux
Les étiquettes multi-niveaux ne sont pas créées par une simple propriété : elles sont lues à partir des données. L'axe des catégories dessine autant de niveaux d'étiquettes qu'il y a de colonnes dans la plage vers laquelle pointe CategoryLabels. La feuille de calcul doit donc être organisée avec la hiérarchie répartie sur les colonnes :
| Colonne A (externe) | Colonne B (interne) | Colonne C (valeurs) |
|---|---|---|
| Nord | Janv. | 120 000 |
| Nord | Févr. | 135 000 |
| Sud | Janv. | 98 000 |
| Sud | Févr. | 110 000 |
Les étiquettes externes de la colonne A sont fusionnées sur les lignes qu'elles couvrent — « Nord » s'étend sur les deux lignes de janv. et févr. C'est cette fusion qui fait que le niveau se réduit visuellement à une seule étiquette par groupe au moment où le graphique est rendu. Sans elle, l'axe affiche toujours deux niveaux, mais le niveau externe répète l'étiquette sur chaque ligne au lieu de regrouper.
Il s'agit d'une question de disposition des données, non d'API de graphique. Le code du graphique doit seulement faire pointer CategoryLabels vers les deux colonnes ; le fait que les cellules externes soient fusionnées se décide dans le classeur, pas dans l'objet graphique.
Créer un graphique avec des étiquettes de catégorie multi-niveaux
Une fois les données disposées, le code du graphique fait deux choses : il fait pointer CategoryLabels vers une plage couvrant à la fois la colonne externe et la colonne interne, et il active MultiLevelLable pour que l'axe développe ces colonnes en lignes empilées. Les étapes sont les suivantes :
- Chargez la police et le fichier de données de test dans le VFS.
- Chargez le classeur et récupérez la feuille de calcul.
- Ajoutez un graphique à colonnes et ajoutez une série de ventes nommée.
- Faites pointer les étiquettes de catégorie vers la colonne de la région et celle du mois.
- Activez les étiquettes multi-niveaux pour l'axe des catégories et enregistrez le classeur.
function App() {
const createMultiLevelChart = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales";
chart.Legend.Delete();
// Add the sales series and give it a name
const serie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
serie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
serie.CategoryLabels = sheet.Range.get("A2:B7");
// Turn on multi-level category labels so each level gets its own row
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "MultiLevelLabels.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Multi-Level Labels</h1>
<button onClick={createMultiLevelChart}>Start</button>
</div>
);
}
export default App;
Un graphique avec des étiquettes de catégorie multi-niveaux, chaque niveau sur sa propre ligne

C'est la plage A2:B7 qui fait afficher deux niveaux à l'axe. Lier une plage d'une seule colonne telle que B2:B7 ne produirait toujours qu'un seul niveau, même avec MultiLevelLable défini sur true — la propriété contrôle si plusieurs niveaux sont développés en lignes, et non si un niveau de données existe à développer.
Pourquoi la série de croissance disparaît
Ajoutez une seconde série pour la croissance d'une année sur l'autre — des valeurs autour de la dizaine, en pourcentage — et tracez-la sur le même axe des valeurs que les ventes. Les colonnes de ventes atteignent 120 000 ; le taux de croissance atteint 12. Sur un axe gradué de 0 à 140 000, le nombre 12 est indiscernable de zéro. La série est bien là, les données sont correctes, et le graphique affiche une ligne plate collée à la ligne de base.
Ce n'est ni un bug des données ni un bug du graphique. C'est l'axe des valeurs qui fait son travail — mapper une plage qui couvre la plus grande série — au détriment de la plus petite. La seule façon de bien voir les deux séries est de donner à chacune sa propre échelle, et c'est ce que fait l'axe secondaire.
Déplacer une série vers l'axe secondaire
La série de croissance est ajoutée sous forme de courbe plutôt que de colonne. Une courbe n'occupe aucune largeur de barre, elle se lit donc clairement face à la série de colonnes qui partage les mêmes catégories. La sortir de l'axe principal tient à une seule propriété : UsePrimaryAxis = false. Les étapes sont les suivantes :
- Chargez la police et le fichier de données de test dans le VFS.
- Chargez le classeur et récupérez la feuille de calcul.
- Ajoutez un graphique à colonnes et ajoutez une série de ventes nommée.
- Ajoutez la série de croissance sous forme de courbe.
- Déplacez la série de croissance vers l'axe secondaire et enregistrez le classeur.
function App() {
const addSecondaryAxis = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales and YoY Growth";
// Add the sales series, which stays on the primary axis
const salesSerie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
salesSerie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
salesSerie.CategoryLabels = sheet.Range.get("A2:B7");
// Add the growth series as a line
const growthSerie = chart.Series.Add({ name: "YoY Growth", serieType: xlsModule.ExcelChartType.Line });
growthSerie.Values = sheet.Range.get("D2:D7");
// Move the growth series to the secondary axis so it plots on its own percentage scale
growthSerie.UsePrimaryAxis = false;
// Turn on multi-level category labels
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "SecondaryAxis.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Secondary Axis</h1>
<button onClick={addSecondaryAxis}>Start</button>
</div>
);
}
export default App;
Un graphique à colonnes avec un axe secondaire pour la série de courbe du taux de croissance

UsePrimaryAxis = false n'affecte que la série sur laquelle il est défini ; toutes les autres séries restent sur l'axe principal. Le graphique gagne une seconde paire d'axes des valeurs et des catégories, ce qui lui donne deux plages d'échelle distinctes. Series.Add prend le nom de la série au même moment, de sorte que la légende affiche le nom transmis plutôt qu'un « Série 1 » généré automatiquement.
Définir l'échelle de l'axe secondaire
Une fois qu'une série passe sur l'axe secondaire, cet axe calcule sa propre échelle — et il le fait indépendamment de l'axe principal. Les deux plages ne se connaissent pas, ce qui signifie que l'axe secondaire peut choisir des bornes qui ne s'accordent pas bien avec les données.
PrimaryValueAxis.MinValue, MaxValue et MajorUnit ne contrôlent que l'axe principal. Pour définir l'échelle de l'axe secondaire, utilisez SecondaryValueAxis :
// Give the secondary axis a 0-20 scale with a major unit of 5
chart.SecondaryValueAxis.MinValue = 0;
chart.SecondaryValueAxis.MaxValue = 20;
chart.SecondaryValueAxis.MajorUnit = 5;
Définissez l'échelle après avoir déplacé la série sur l'axe secondaire. Tant qu'aucune série n'utilise l'axe secondaire, l'affectation est acceptée mais jamais écrite dans le fichier — l'axe n'existe pas dans le résultat tant qu'une série n'y est pas tracée.
Problèmes courants
L'axe des catégories n'affiche qu'un seul niveau d'étiquettes.
CategoryLabels pointe vers une plage d'une seule colonne. Le nombre de niveaux est déterminé par le nombre de colonnes que couvre la plage, et non par la propriété MultiLevelLable. Pointez vers une plage multi-colonnes telle que A2:B7, et assurez-vous que les cellules d'étiquettes externes sont fusionnées dans les données.
L'échelle de l'axe secondaire semble incorrecte.
Les axes des valeurs principal et secondaire calculent leurs échelles indépendamment. Définir MinValue ou MaxValue sur PrimaryValueAxis n'affecte pas l'axe secondaire. Utilisez chart.SecondaryValueAxis pour définir directement son échelle, et faites-le après avoir déplacé une série dessus.
La série de croissance apparaît toujours plate après l'ajout d'un axe secondaire.
Vérifiez que UsePrimaryAxis = false est défini sur la série de croissance, et non sur la série de ventes. La propriété s'applique série par série — la définir sur la mauvaise série déplace la mauvaise vers l'axe secondaire.
La légende affiche « Série 1 » au lieu du nom de la série.
Le nom n'a pas été transmis à Series.Add. Utilisez chart.Series.Add({ name: "Sales", ... }) afin que la légende reprenne le nom souhaité plutôt qu'une étiquette générée automatiquement.
FAQ
Puis-je avoir plus de deux niveaux d'étiquettes de catégorie ?
Oui. Le nombre de niveaux est déterminé par le nombre de colonnes que couvre la plage CategoryLabels. Une plage de trois colonnes produit trois niveaux — par exemple, année, trimestre et mois. Les cellules d'étiquettes externes doivent être fusionnées dans les données pour que chaque niveau se regroupe correctement.
L'axe secondaire fonctionne-t-il avec des types de graphiques autres que les colonnes et les courbes ?
Oui. L'axe secondaire n'est pas lié à un type de graphique précis. Le schéma courant est colonnes plus courbe — la courbe n'occupe aucune largeur de barre et se lit clairement face aux colonnes — mais n'importe quelle série peut être déplacée vers l'axe secondaire en définissant UsePrimaryAxis = false.
Dois-je installer Excel pour créer ces graphiques ?
Non. Le moteur de feuille de calcul est fourni avec le package et s'exécute en WebAssembly dans le navigateur. Le classeur est créé, mis en graphique et enregistré entièrement côté client.
Puis-je contrôler séparément l'axe des catégories secondaire ?
Lorsqu'une série passe sur l'axe secondaire, le graphique gagne un axe des catégories secondaire en plus de l'axe des valeurs secondaire. Les deux axes des catégories partagent les mêmes étiquettes de catégorie par défaut, de sorte que les étiquettes multi-niveaux s'appliquent aux deux.
Le fichier de sortie est-il compatible avec Excel ?
Oui. Le classeur est enregistré au format .xlsx, et le graphique — y compris les étiquettes multi-niveaux et l'axe secondaire — est écrit sous forme de XML de graphique standard qu'Excel lit nativement.
Voir aussi
Gráficos de Excel más claros en JavaScript: etiquetas multinivel y ejes duales
Tabla de contenidos
- Cuando un eje no es suficiente
- Requisitos previos
- Los datos detrás de las etiquetas de varios niveles
- Crear un gráfico con etiquetas de categoría de varios niveles
- Por qué desaparece la serie de crecimiento
- Mover una serie al eje secundario
- Configurar la escala del eje secundario
- Problemas comunes
- Preguntas frecuentes
- Véase también

Un gráfico de columnas con regiones y meses en el mismo eje tiene dos problemas, y no son el mismo problema. El primero es que las etiquetas de categoría se colapsan en una sola fila — "North", "Jan", "North", "Feb" — y el lector tiene que reagrupar mentalmente qué mes pertenece a qué región. El segundo es que cuando se añade una serie de tasa de crecimiento junto a una serie de ventas que llega a los millones, la tasa de crecimiento se convierte en una línea plana pegada a la línea base, porque un solo eje de valores no puede servir a dos magnitudes a la vez.
Las etiquetas de categoría de varios niveles solucionan lo primero. Un eje secundario soluciona lo segundo. Son características independientes que resultan útiles en el mismo gráfico, y Spire.XLS for JavaScript maneja ambas a través de la API de ejes del gráfico — directamente en el navegador sobre WebAssembly, con archivos que circulan por un sistema de archivos virtual (VFS) y sin necesidad de backend.
Para la configuración del proyecto, consulte Integrating Spire.XLS for JavaScript in a React Project. Los siguientes ejemplos asumen que el paquete está instalado y que el módulo WebAssembly se ha inicializado.
Cuando un eje no es suficiente
Los dos problemas aparecen en el mismo tipo de hoja de cálculo — una en la que las categorías tienen una jerarquía y los valores tienen una dispersión — pero provienen de lugares diferentes:
| Problema | De dónde viene | Cómo se ve el gráfico | Qué lo soluciona |
|---|---|---|---|
| Las etiquetas se amontonan en una sola fila | Las categorías son jerárquicas (región → mes, año → trimestre) pero el eje las trata como planas | Una sola fila de etiquetas donde las categorías externas e internas se alternan sin agrupación visual | Etiquetas de categoría de varios niveles |
| Una serie se aplana hasta convertirse en una línea | Dos series difieren en órdenes de magnitud (ventas en millones, crecimiento en porcentaje) pero comparten un solo eje de valores | La serie más pequeña se comprime hasta casi cero y su variación resulta invisible | Eje secundario |
Ninguno de los dos es un problema de estilo. Ambos tienen que ver con que el eje no sabe algo que necesita saber — que las categorías tienen capas, o que los valores tienen escalas incompatibles. Las dos secciones siguientes los abordan por turnos, y la segunda se apoya en la primera para que el gráfico final incluya ambas correcciones.
Requisitos previos
Necesita un proyecto de React con Spire.XLS for JavaScript instalado y el módulo WebAssembly inicializado, accesible en window.wasmModule.spirexls. El ejemplo carga una fuente y un archivo de datos preconstruido en el VFS antes de crear el gráfico, y ambos se obtienen de la carpeta pública del proyecto.
Los datos detrás de las etiquetas de varios niveles
Las etiquetas de varios niveles no se crean solo con una propiedad — se leen de los datos. El eje de categorías dibuja tantos niveles de etiquetas como columnas haya en el rango al que apunta CategoryLabels. Por lo tanto, la hoja de cálculo debe estar organizada con la jerarquía distribuida en columnas:
| Columna A (externa) | Columna B (interna) | Columna C (valores) |
|---|---|---|
| North | Jan | 120,000 |
| North | Feb | 135,000 |
| South | Jan | 98,000 |
| South | Feb | 110,000 |
Las etiquetas externas de la columna A están combinadas a lo largo de las filas que abarcan — "North" abarca las dos filas de Jan y Feb. Esa combinación es lo que hace que el nivel se colapse visualmente en una sola etiqueta por grupo cuando se representa el gráfico. Sin ella, el eje sigue mostrando dos niveles, pero el nivel externo repite la etiqueta en cada fila en lugar de agrupar.
Esto es una cuestión de diseño de datos, no de la API de gráficos. El código del gráfico solo tiene que apuntar CategoryLabels a ambas columnas; si las celdas externas están combinadas se decide en el libro de trabajo, no en el objeto del gráfico.
Crear un gráfico con etiquetas de categoría de varios niveles
Una vez organizados los datos, el código del gráfico hace dos cosas: apunta CategoryLabels a un rango que abarca tanto la columna externa como la interna, y activa MultiLevelLable para que el eje expanda esas columnas en filas apiladas. Los pasos son:
- Cargar la fuente y el archivo de datos de prueba en el VFS.
- Cargar el libro de trabajo y obtener la hoja de cálculo.
- Añadir un gráfico de columnas y añadir una serie de ventas con nombre.
- Apuntar las etiquetas de categoría tanto a la columna de región como a la de mes.
- Activar las etiquetas de varios niveles para el eje de categorías y guardar el libro de trabajo.
function App() {
const createMultiLevelChart = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales";
chart.Legend.Delete();
// Add the sales series and give it a name
const serie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
serie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
serie.CategoryLabels = sheet.Range.get("A2:B7");
// Turn on multi-level category labels so each level gets its own row
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "MultiLevelLabels.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Multi-Level Labels</h1>
<button onClick={createMultiLevelChart}>Start</button>
</div>
);
}
export default App;
Un gráfico con etiquetas de categoría de varios niveles, cada nivel en su propia fila

El rango A2:B7 es lo que hace que el eje muestre dos niveles. Enlazar un rango de una sola columna como B2:B7 seguiría produciendo un solo nivel incluso con MultiLevelLable establecido en true — la propiedad controla si se expanden varios niveles en filas, no si existe un nivel de datos que expandir.
Por qué desaparece la serie de crecimiento
Añada una segunda serie para el crecimiento interanual — valores en la decena baja, porcentajes — y represéntela en el mismo eje de valores que las ventas. Las columnas de ventas alcanzan 120,000; la tasa de crecimiento alcanza 12. En un eje que va de 0 a 140,000, el número 12 es indistinguible de cero. La serie está ahí, los datos son correctos, y el gráfico muestra una línea plana pegada a la línea base.
Esto no es un error en los datos ni en el gráfico. Es el eje de valores haciendo su trabajo — mapear un rango que cubre la serie más grande — a costa de la más pequeña. La única forma de ver claramente ambas series es darle a cada una su propia escala, y eso es lo que hace el eje secundario.
Mover una serie al eje secundario
La serie de crecimiento se añade como línea en lugar de como columna. Una línea no ocupa ancho de barra, así que se lee con claridad frente a la serie de columnas que comparte las mismas categorías. Moverla fuera del eje primario es una sola propiedad: UsePrimaryAxis = false. Los pasos son:
- Cargar la fuente y el archivo de datos de prueba en el VFS.
- Cargar el libro de trabajo y obtener la hoja de cálculo.
- Añadir un gráfico de columnas y añadir una serie de ventas con nombre.
- Añadir la serie de crecimiento como línea.
- Mover la serie de crecimiento al eje secundario y guardar el libro de trabajo.
function App() {
const addSecondaryAxis = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales and YoY Growth";
// Add the sales series, which stays on the primary axis
const salesSerie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
salesSerie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
salesSerie.CategoryLabels = sheet.Range.get("A2:B7");
// Add the growth series as a line
const growthSerie = chart.Series.Add({ name: "YoY Growth", serieType: xlsModule.ExcelChartType.Line });
growthSerie.Values = sheet.Range.get("D2:D7");
// Move the growth series to the secondary axis so it plots on its own percentage scale
growthSerie.UsePrimaryAxis = false;
// Turn on multi-level category labels
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "SecondaryAxis.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Secondary Axis</h1>
<button onClick={addSecondaryAxis}>Start</button>
</div>
);
}
export default App;
Un gráfico de columnas con un eje secundario para la serie de línea de la tasa de crecimiento

UsePrimaryAxis = false afecta solo a la serie en la que se establece; todas las demás series permanecen en el eje primario. El gráfico gana un segundo par de ejes de valores y de categorías, lo que le da dos rangos de escala separados. Series.Add toma el nombre de la serie al mismo tiempo, así que la leyenda muestra el nombre pasado en lugar de un "Series 1" autogenerado.
Configurar la escala del eje secundario
Una vez que una serie se mueve al eje secundario, ese eje calcula su propia escala — y lo hace de forma independiente del primario. Los dos rangos no conocen nada el uno del otro, lo que significa que el eje secundario puede elegir límites que no se alinean bien con los datos.
PrimaryValueAxis.MinValue, MaxValue y MajorUnit controlan solo el eje primario. Para establecer la escala del eje secundario, utilice SecondaryValueAxis:
// Give the secondary axis a 0-20 scale with a major unit of 5
chart.SecondaryValueAxis.MinValue = 0;
chart.SecondaryValueAxis.MaxValue = 20;
chart.SecondaryValueAxis.MajorUnit = 5;
Establezca la escala después de que la serie se haya movido al eje secundario. Mientras ninguna serie utilice el eje secundario, la asignación se acepta pero nunca se escribe en el archivo — el eje no existe en la salida hasta que se representa una serie sobre él.
Problemas comunes
El eje de categorías muestra solo un nivel de etiquetas.
CategoryLabels está apuntando a un rango de una sola columna. El número de niveles lo decide cuántas columnas abarca el rango, no la propiedad MultiLevelLable. Apunte a un rango de varias columnas como A2:B7, y asegúrese de que las celdas de etiqueta externas estén combinadas en los datos.
La escala del eje secundario parece incorrecta.
Los ejes de valores primario y secundario calculan sus escalas de forma independiente. Establecer MinValue o MaxValue en PrimaryValueAxis no afecta al eje secundario. Utilice chart.SecondaryValueAxis para establecer su escala directamente, y hágalo después de mover una serie a él.
La serie de crecimiento sigue apareciendo plana tras añadir un eje secundario.
Compruebe que UsePrimaryAxis = false esté establecido en la serie de crecimiento, no en la serie de ventas. La propiedad es por serie — establecerla en la serie equivocada mueve la serie equivocada al eje secundario.
La leyenda muestra "Series 1" en lugar del nombre de la serie.
El nombre no se pasó a Series.Add. Utilice chart.Series.Add({ name: "Sales", ... }) para que la leyenda tome el nombre que pretendía en lugar de una etiqueta autogenerada.
Preguntas frecuentes
¿Puedo tener más de dos niveles de etiquetas de categoría?
Sí. El número de niveles lo determina el número de columnas que abarca el rango de CategoryLabels. Un rango de tres columnas produce tres niveles — por ejemplo, año, trimestre y mes. Las celdas de etiqueta externas deben estar combinadas en los datos para que cada nivel se agrupe correctamente.
¿Funciona el eje secundario con tipos de gráfico distintos de columnas y líneas?
Sí. El eje secundario no está vinculado a un tipo de gráfico específico. El patrón habitual es columnas más línea — la línea no ocupa ancho de barra y se lee con claridad frente a las columnas — pero cualquier serie puede moverse al eje secundario estableciendo UsePrimaryAxis = false.
¿Necesito tener Excel instalado para crear estos gráficos?
No. El motor de hojas de cálculo viene con el paquete y se ejecuta como WebAssembly en el navegador. El libro de trabajo se construye, se grafica y se guarda por completo en el lado del cliente.
¿Puedo controlar el eje de categorías secundario por separado?
Cuando una serie se mueve al eje secundario, el gráfico gana un eje de categorías secundario además del eje de valores secundario. Los dos ejes de categorías comparten las mismas etiquetas de categoría de forma predeterminada, así que las etiquetas de varios niveles se aplican a ambos.
¿Es el archivo de salida compatible con Excel?
Sí. El libro de trabajo se guarda como .xlsx, y el gráfico — incluidas las etiquetas de varios niveles y el eje secundario — se escribe como XML de gráfico estándar que Excel lee de forma nativa.
Véase también
Klarere Excel-Diagramme in JavaScript: Mehrstufige Beschriftungen & duale Achsen
Inhaltsverzeichnis
- Wenn eine Achse nicht ausreicht
- Voraussetzungen
- Die Daten hinter mehrstufigen Beschriftungen
- Ein Diagramm mit mehrstufigen Kategoriebeschriftungen erstellen
- Warum die Wachstumsreihe verschwindet
- Eine Reihe auf die Sekundärachse verschieben
- Die Skalierung der Sekundärachse festlegen
- Häufige Probleme
- FAQ
- Siehe auch

Ein Säulendiagramm mit Regionen und Monaten auf derselben Achse hat zwei Probleme, und diese Probleme sind nicht dieselben. Das erste ist, dass die Kategoriebeschriftungen in einer einzigen Zeile zusammenfallen — "Nord", "Jan", "Nord", "Feb" — und der Leser mental neu gruppieren muss, welcher Monat zu welcher Region gehört. Das zweite ist, dass wenn eine Wachstumsraten-Reihe neben einer Umsatzreihe hinzugefügt wird, die in die Millionen geht, die Wachstumsrate zu einer flachen Linie wird, die an der Grundlinie klebt, weil eine einzige Wertachse nicht zwei Größenordnungen gleichzeitig bedienen kann.
Mehrstufige Kategoriebeschriftungen beheben das erste Problem. Eine Sekundärachse behebt das zweite. Es sind unabhängige Funktionen, die zufällig im selben Diagramm nützlich sind, und Spire.XLS for JavaScript behandelt beide über die Diagrammachsen-API — direkt im Browser auf WebAssembly, wobei Dateien durch ein virtuelles Dateisystem (VFS) laufen und kein Backend beteiligt ist.
Zur Projekteinrichtung siehe Spire.XLS for JavaScript in ein React-Projekt integrieren. Die folgenden Beispiele gehen davon aus, dass das Paket installiert und das WebAssembly-Modul initialisiert wurde.
Wenn eine Achse nicht ausreicht
Die beiden Probleme treten in derselben Art von Arbeitsblatt auf — eines, bei dem die Kategorien eine Hierarchie haben und die Werte eine Streuung aufweisen —, aber sie stammen von unterschiedlichen Stellen:
| Problem | Woher es kommt | Wie das Diagramm aussieht | Was es behebt |
|---|---|---|---|
| Beschriftungen stapeln sich in einer Zeile | Kategorien sind hierarchisch (Region → Monat, Jahr → Quartal), aber die Achse behandelt sie als flach | Eine einzige Zeile mit Beschriftungen, in der äußere und innere Kategorien ohne visuelle Gruppierung abwechseln | Mehrstufige Kategoriebeschriftungen |
| Eine Reihe wird zu einer flachen Linie | Zwei Reihen unterscheiden sich um Größenordnungen (Umsatz in Millionen, Wachstum in Prozent), teilen sich aber eine einzige Wertachse | Die kleinere Reihe wird auf nahezu null komprimiert und ihre Variation ist unsichtbar | Sekundärachse |
Keines von beiden ist ein Styling-Problem. Bei beiden geht es darum, dass die Achse etwas nicht weiß, was sie wissen müsste — dass die Kategorien Ebenen haben oder dass die Werte inkompatible Skalen haben. Die beiden folgenden Abschnitte behandeln sie der Reihe nach, und der zweite baut auf dem ersten auf, sodass das endgültige Diagramm beide Korrekturen enthält.
Voraussetzungen
Sie benötigen ein React-Projekt mit installiertem Spire.XLS for JavaScript und einem initialisierten WebAssembly-Modul, erreichbar unter window.wasmModule.spirexls. Das Beispiel lädt eine Schriftart und eine vorbereitete Datendatei in das VFS, bevor das Diagramm erstellt wird, und beide werden aus dem öffentlichen Ordner des Projekts abgerufen.
Die Daten hinter mehrstufigen Beschriftungen
Mehrstufige Beschriftungen werden nicht allein durch eine Eigenschaft erstellt — sie werden aus den Daten gelesen. Die Kategorieachse zeichnet so viele Beschriftungsebenen, wie es Spalten in dem Bereich gibt, auf den CategoryLabels zeigt. Daher muss das Arbeitsblatt mit der Hierarchie über die Spalten hinweg angelegt werden:
| Spalte A (äußere) | Spalte B (innere) | Spalte C (Werte) |
|---|---|---|
| Nord | Jan | 120.000 |
| Nord | Feb | 135.000 |
| Süd | Jan | 98.000 |
| Süd | Feb | 110.000 |
Die äußeren Beschriftungen in Spalte A sind über die Zeilen, die sie abdecken, verbunden — "Nord" erstreckt sich über die beiden Zeilen für Jan und Feb. Diese Zusammenführung ist es, die die Ebene beim Rendern des Diagramms visuell zu einer einzigen Beschriftung pro Gruppe zusammenfallen lässt. Ohne sie zeigt die Achse zwar weiterhin zwei Ebenen, aber die äußere Ebene wiederholt die Beschriftung in jeder Zeile, statt zu gruppieren.
Dies ist eine Frage des Datenlayouts, nicht der Diagramm-API. Der Diagrammcode muss CategoryLabels nur auf beide Spalten zeigen lassen; ob die äußeren Zellen verbunden sind, wird in der Arbeitsmappe entschieden, nicht im Diagrammobjekt.
Ein Diagramm mit mehrstufigen Kategoriebeschriftungen erstellen
Sobald die Daten angelegt sind, tut der Diagrammcode zwei Dinge: Er zeigt CategoryLabels auf einen Bereich, der sowohl die äußere als auch die innere Spalte umfasst, und er aktiviert MultiLevelLable, damit die Achse diese Spalten zu gestapelten Zeilen erweitert. Die Schritte sind:
- Laden Sie die Schriftart und die Testdatendatei in das VFS.
- Laden Sie die Arbeitsmappe und holen Sie das Arbeitsblatt.
- Fügen Sie ein Säulendiagramm hinzu und fügen Sie eine benannte Umsatzreihe hinzu.
- Richten Sie die Kategoriebeschriftungen sowohl auf die Regions- als auch auf die Monatsspalte.
- Aktivieren Sie mehrstufige Beschriftungen für die Kategorieachse und speichern Sie die Arbeitsmappe.
function App() {
const createMultiLevelChart = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales";
chart.Legend.Delete();
// Add the sales series and give it a name
const serie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
serie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
serie.CategoryLabels = sheet.Range.get("A2:B7");
// Turn on multi-level category labels so each level gets its own row
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "MultiLevelLabels.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Multi-Level Labels</h1>
<button onClick={createMultiLevelChart}>Start</button>
</div>
);
}
export default App;
Ein Diagramm mit mehrstufigen Kategoriebeschriftungen, jede Ebene in einer eigenen Zeile

Der Bereich A2:B7 ist es, der die Achse zwei Ebenen anzeigen lässt. Das Binden eines einspaltigen Bereichs wie B2:B7 würde auch bei auf true gesetztem MultiLevelLable nur eine Ebene erzeugen — die Eigenschaft steuert, ob mehrere Ebenen in Zeilen erweitert werden, nicht, ob überhaupt eine Datenebene zum Erweitern vorhanden ist.
Warum die Wachstumsreihe verschwindet
Fügen Sie eine zweite Reihe für das Jahr-über-Jahr-Wachstum hinzu — Werte im niedrigen zweistelligen Prozentbereich — und tragen Sie sie auf derselben Wertachse wie den Umsatz auf. Die Umsatzsäulen erreichen 120.000; die Wachstumsrate erreicht 12. Auf einer Achse, die von 0 bis 140.000 skaliert, ist die Zahl 12 nicht von null zu unterscheiden. Die Reihe ist vorhanden, die Daten sind korrekt, und das Diagramm zeigt eine flache Linie an der Grundlinie.
Dies ist kein Fehler in den Daten oder im Diagramm. Es ist die Wertachse, die ihre Aufgabe erfüllt — einen Bereich abbildet, der die größte Reihe abdeckt — auf Kosten der kleinsten. Die einzige Möglichkeit, beide Reihen klar zu sehen, besteht darin, jeder ihre eigene Skala zu geben, und genau das tut die Sekundärachse.
Eine Reihe auf die Sekundärachse verschieben
Die Wachstumsreihe wird als Linie statt als Säule hinzugefügt. Eine Linie beansprucht keine Balkenbreite und lässt sich daher klar neben der Säulenreihe lesen, die dieselben Kategorien teilt. Sie von der primären Achse zu entfernen ist eine einzige Eigenschaft: UsePrimaryAxis = false. Die Schritte sind:
- Laden Sie die Schriftart und die Testdatendatei in das VFS.
- Laden Sie die Arbeitsmappe und holen Sie das Arbeitsblatt.
- Fügen Sie ein Säulendiagramm hinzu und fügen Sie eine benannte Umsatzreihe hinzu.
- Fügen Sie die Wachstumsreihe als Linie hinzu.
- Verschieben Sie die Wachstumsreihe auf die Sekundärachse und speichern Sie die Arbeitsmappe.
function App() {
const addSecondaryAxis = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales and YoY Growth";
// Add the sales series, which stays on the primary axis
const salesSerie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
salesSerie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
salesSerie.CategoryLabels = sheet.Range.get("A2:B7");
// Add the growth series as a line
const growthSerie = chart.Series.Add({ name: "YoY Growth", serieType: xlsModule.ExcelChartType.Line });
growthSerie.Values = sheet.Range.get("D2:D7");
// Move the growth series to the secondary axis so it plots on its own percentage scale
growthSerie.UsePrimaryAxis = false;
// Turn on multi-level category labels
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "SecondaryAxis.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Secondary Axis</h1>
<button onClick={addSecondaryAxis}>Start</button>
</div>
);
}
export default App;
Ein Säulendiagramm mit einer Sekundärachse für die Linienreihe der Wachstumsrate

UsePrimaryAxis = false wirkt sich nur auf die Reihe aus, bei der es gesetzt ist; jede andere Reihe bleibt auf der primären Achse. Das Diagramm erhält ein zweites Paar aus Wert- und Kategorieachse, wodurch es zwei separate Skalenbereiche hat. Series.Add nimmt den Reihennamen gleichzeitig entgegen, sodass die Legende den übergebenen Namen anzeigt und nicht ein automatisch generiertes "Series 1".
Die Skalierung der Sekundärachse festlegen
Sobald eine Reihe auf die Sekundärachse verschoben wurde, berechnet diese Achse ihre eigene Skalierung — und zwar unabhängig von der primären. Die beiden Bereiche wissen nichts voneinander, was bedeutet, dass die Sekundärachse Grenzen wählen kann, die nicht gut zu den Daten passen.
PrimaryValueAxis.MinValue, MaxValue und MajorUnit steuern nur die primäre Achse. Um die Skalierung der Sekundärachse festzulegen, verwenden Sie SecondaryValueAxis:
// Give the secondary axis a 0-20 scale with a major unit of 5
chart.SecondaryValueAxis.MinValue = 0;
chart.SecondaryValueAxis.MaxValue = 20;
chart.SecondaryValueAxis.MajorUnit = 5;
Legen Sie die Skalierung nach dem Verschieben der Reihe auf die Sekundärachse fest. Solange keine Reihe die Sekundärachse verwendet, wird die Zuweisung akzeptiert, aber nie in die Datei geschrieben — die Achse existiert in der Ausgabe erst, wenn eine Reihe darauf dargestellt wird.
Häufige Probleme
Die Kategorieachse zeigt nur eine Ebene von Beschriftungen.
CategoryLabels zeigt auf einen einspaltigen Bereich. Die Anzahl der Ebenen wird dadurch bestimmt, wie viele Spalten der Bereich umfasst, nicht durch die Eigenschaft MultiLevelLable. Richten Sie es auf einen mehrspaltigen Bereich wie A2:B7, und stellen Sie sicher, dass die äußeren Beschriftungszellen in den Daten verbunden sind.
Die Skalierung der Sekundärachse sieht falsch aus.
Die primäre und die sekundäre Wertachse berechnen ihre Skalierungen unabhängig voneinander. Das Setzen von MinValue oder MaxValue auf PrimaryValueAxis wirkt sich nicht auf die Sekundärachse aus. Verwenden Sie chart.SecondaryValueAxis, um ihre Skalierung direkt festzulegen, und tun Sie dies, nachdem Sie eine Reihe darauf verschoben haben.
Die Wachstumsreihe erscheint auch nach dem Hinzufügen einer Sekundärachse noch flach.
Prüfen Sie, ob UsePrimaryAxis = false bei der Wachstumsreihe gesetzt ist und nicht bei der Umsatzreihe. Die Eigenschaft gilt pro Reihe — wenn Sie sie bei der falschen Reihe setzen, wird die falsche auf die Sekundärachse verschoben.
Die Legende zeigt "Series 1" statt des Reihennamens.
Der Name wurde nicht an Series.Add übergeben. Verwenden Sie chart.Series.Add({ name: "Sales", ... }), damit die Legende den von Ihnen beabsichtigten Namen übernimmt und nicht eine automatisch generierte Beschriftung.
FAQ
Kann ich mehr als zwei Ebenen von Kategoriebeschriftungen haben?
Ja. Die Anzahl der Ebenen wird durch die Anzahl der Spalten bestimmt, die der Bereich CategoryLabels umfasst. Ein dreispaltiger Bereich erzeugt drei Ebenen — zum Beispiel Jahr, Quartal und Monat. Die äußeren Beschriftungszellen müssen in den Daten verbunden sein, damit jede Ebene korrekt gruppiert wird.
Funktioniert die Sekundärachse auch mit anderen Diagrammtypen als Säule und Linie?
Ja. Die Sekundärachse ist nicht an einen bestimmten Diagrammtyp gebunden. Das übliche Muster ist Säule plus Linie — die Linie beansprucht keine Balkenbreite und lässt sich klar neben den Säulen lesen —, aber jede Reihe kann durch Setzen von UsePrimaryAxis = false auf die Sekundärachse verschoben werden.
Muss Excel installiert sein, um diese Diagramme zu erstellen?
Nein. Die Tabellenkalkulations-Engine ist im Paket enthalten und läuft als WebAssembly im Browser. Die Arbeitsmappe wird vollständig clientseitig erstellt, mit Diagrammen versehen und gespeichert.
Kann ich die sekundäre Kategorieachse separat steuern?
Wenn eine Reihe auf die Sekundärachse verschoben wird, erhält das Diagramm zusätzlich zur sekundären Wertachse eine sekundäre Kategorieachse. Die beiden Kategorieachsen teilen sich standardmäßig dieselben Kategoriebeschriftungen, sodass mehrstufige Beschriftungen für beide gelten.
Ist die Ausgabedatei mit Excel kompatibel?
Ja. Die Arbeitsmappe wird als .xlsx gespeichert, und das Diagramm — einschließlich mehrstufiger Beschriftungen und Sekundärachse — wird als standardmäßiges Diagramm-XML geschrieben, das Excel nativ liest.
Siehe auch
Понятные диаграммы Excel на JavaScript: многоуровневые подписи и двойные оси
Содержание
- Когда одной оси недостаточно
- Предварительные требования
- Данные, лежащие в основе многоуровневых подписей
- Создание диаграммы с многоуровневыми подписями категорий
- Почему ряд роста исчезает
- Перемещение ряда на вспомогательную ось
- Настройка шкалы вспомогательной оси
- Типичные проблемы
- Часто задаваемые вопросы
- См. также

Гистограмма с регионами и месяцами на одной и той же оси имеет две проблемы, и это не одна и та же проблема. Первая — подписи категорий сливаются в одну строку — "North", "Jan", "North", "Feb" — и читателю приходится мысленно заново группировать, какой месяц относится к какому региону. Вторая — когда ряд темпов роста добавляется рядом с рядом продаж, измеряемым миллионами, темп роста превращается в плоскую линию, прижатую к базовой линии, потому что одна ось значений не может обслуживать два порядка величин одновременно.
Многоуровневые подписи категорий решают первую проблему. Вспомогательная ось решает вторую. Это независимые возможности, которые просто оказываются полезны на одной диаграмме, и Spire.XLS for JavaScript поддерживает обе через API осей диаграммы — прямо в браузере на WebAssembly, с перемещением файлов через виртуальную файловую систему (VFS) и без участия серверной части.
О настройке проекта см. в разделе Интеграция Spire.XLS for JavaScript в проект React. Примеры ниже предполагают, что пакет установлен, а модуль WebAssembly инициализирован.
Когда одной оси недостаточно
Обе проблемы встречаются на одном и том же типе листа — там, где категории имеют иерархию, а значения сильно различаются по величине, — но возникают они по разным причинам:
| Проблема | Из-за чего возникает | Как выглядит диаграмма | Что это исправляет |
|---|---|---|---|
| Подписи скучиваются в одну строку | Категории иерархичны (регион → месяц, год → квартал), но ось обрабатывает их как плоские | Одна строка подписей, где внешние и внутренние категории чередуются без визуальной группировки | Многоуровневые подписи категорий |
| Один ряд вырождается в линию | Два ряда различаются на порядки (продажи в миллионах, рост в процентах), но используют одну ось значений | Меньший ряд сжимается почти до нуля, и его вариация не видна | Вспомогательная ось |
Ни то, ни другое не является проблемой оформления. Обе связаны с тем, что ось не знает того, что ей нужно знать, — что категории имеют уровни или что значения имеют несовместимые шкалы. Два раздела ниже рассматривают их по очереди, причём второй опирается на первый, так что итоговая диаграмма содержит оба исправления.
Предварительные требования
Вам понадобится проект React с установленным Spire.XLS for JavaScript и инициализированным модулем WebAssembly, доступным по адресу window.wasmModule.spirexls. Пример загружает шрифт и заранее подготовленный файл данных в VFS перед созданием диаграммы; оба файла берутся из папки public проекта.
Данные, лежащие в основе многоуровневых подписей
Многоуровневые подписи не создаются одним лишь свойством — они считываются из данных. Ось категорий отрисовывает столько уровней подписей, сколько столбцов содержит диапазон, на который указывает CategoryLabels. Поэтому лист должен быть организован так, чтобы иерархия располагалась по столбцам:
| Столбец A (внешний) | Столбец B (внутренний) | Столбец C (значения) |
|---|---|---|
| North | Jan | 120,000 |
| North | Feb | 135,000 |
| South | Jan | 98,000 |
| South | Feb | 110,000 |
Внешние подписи в столбце A объединены по строкам, которые они охватывают, — "North" охватывает две строки для Jan и Feb. Именно это объединение приводит к тому, что при отрисовке диаграммы уровень визуально сворачивается в одну подпись на группу. Без него ось всё равно показывает два уровня, но внешний уровень повторяет подпись в каждой строке вместо группировки.
Это вопрос компоновки данных, а не API диаграмм. Коду диаграммы достаточно указать CategoryLabels на оба столбца; объединены ли внешние ячейки — решается в книге, а не в объекте диаграммы.
Создание диаграммы с многоуровневыми подписями категорий
Когда данные разложены, код диаграммы делает две вещи: указывает CategoryLabels на диапазон, охватывающий и внешний, и внутренний столбец, и включает MultiLevelLable, чтобы ось развернула эти столбцы в расположенные друг над другом строки. Шаги таковы:
- Загрузите шрифт и файл тестовых данных в VFS.
- Загрузите книгу и получите лист.
- Добавьте гистограмму и добавьте именованный ряд продаж.
- Укажите подписи категорий на столбец региона и на столбец месяца.
- Включите многоуровневые подписи для оси категорий и сохраните книгу.
function App() {
const createMultiLevelChart = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales";
chart.Legend.Delete();
// Add the sales series and give it a name
const serie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
serie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
serie.CategoryLabels = sheet.Range.get("A2:B7");
// Turn on multi-level category labels so each level gets its own row
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "MultiLevelLabels.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Multi-Level Labels</h1>
<button onClick={createMultiLevelChart}>Start</button>
</div>
);
}
export default App;
Диаграмма с многоуровневыми подписями категорий, каждый уровень в своей строке

Диапазон A2:B7 — это то, что заставляет ось показывать два уровня. Привязка одностолбцового диапазона, например B2:B7, всё равно даст один уровень, даже если для MultiLevelLable задано значение true, — свойство управляет тем, разворачиваются ли несколько уровней в строки, а не тем, существует ли уровень данных для разворачивания.
Почему ряд роста исчезает
Добавьте второй ряд для годового роста — значения в районе 12–13, проценты — и постройте его на той же оси значений, что и продажи. Столбцы продаж достигают 120 000; темп роста достигает 12. На оси с диапазоном от 0 до 140 000 число 12 неотличимо от нуля. Ряд присутствует, данные верны, а диаграмма показывает линию, плоскую у базовой линии.
Это не ошибка ни в данных, ни в диаграмме. Это ось значений делает свою работу — отображает диапазон, охватывающий наибольший ряд, — за счёт наименьшего. Единственный способ ясно увидеть оба ряда — дать каждому свою шкалу, и именно это делает вспомогательная ось.
Перемещение ряда на вспомогательную ось
Ряд роста добавляется как линия, а не как столбец. Линия не занимает ширину столбца, поэтому она чётко читается на фоне ряда столбцов, использующего те же категории. Чтобы убрать её с основной оси, достаточно одного свойства: UsePrimaryAxis = false. Шаги таковы:
- Загрузите шрифт и файл тестовых данных в VFS.
- Загрузите книгу и получите лист.
- Добавьте гистограмму и добавьте именованный ряд продаж.
- Добавьте ряд роста как линию.
- Переместите ряд роста на вспомогательную ось и сохраните книгу.
function App() {
const addSecondaryAxis = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales and YoY Growth";
// Add the sales series, which stays on the primary axis
const salesSerie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
salesSerie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
salesSerie.CategoryLabels = sheet.Range.get("A2:B7");
// Add the growth series as a line
const growthSerie = chart.Series.Add({ name: "YoY Growth", serieType: xlsModule.ExcelChartType.Line });
growthSerie.Values = sheet.Range.get("D2:D7");
// Move the growth series to the secondary axis so it plots on its own percentage scale
growthSerie.UsePrimaryAxis = false;
// Turn on multi-level category labels
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "SecondaryAxis.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Secondary Axis</h1>
<button onClick={addSecondaryAxis}>Start</button>
</div>
);
}
export default App;
Гистограмма со вспомогательной осью для линейного ряда темпа роста

UsePrimaryAxis = false влияет только на тот ряд, для которого оно задано; все остальные ряды остаются на основной оси. Диаграмма приобретает вторую пару осей — значений и категорий, — что даёт ей два отдельных диапазона шкал. Series.Add принимает имя ряда одновременно, поэтому в легенде отображается переданное имя, а не автоматически созданное "Series 1".
Настройка шкалы вспомогательной оси
Как только ряд перемещается на вспомогательную ось, эта ось вычисляет собственную шкалу — независимо от основной. Два диапазона ничего не знают друг о друге, поэтому вспомогательная ось может выбрать границы, которые плохо согласуются с данными.
PrimaryValueAxis.MinValue, MaxValue и MajorUnit управляют только основной осью. Чтобы задать шкалу вспомогательной оси, используйте SecondaryValueAxis:
// Give the secondary axis a 0-20 scale with a major unit of 5
chart.SecondaryValueAxis.MinValue = 0;
chart.SecondaryValueAxis.MaxValue = 20;
chart.SecondaryValueAxis.MajorUnit = 5;
Задавайте шкалу после того, как ряд был перемещён на вспомогательную ось. Пока ни один ряд не использует вспомогательную ось, присваивание принимается, но никогда не записывается в файл — оси не существует в выходных данных, пока на неё не построен ряд.
Типичные проблемы
Ось категорий показывает только один уровень подписей.
CategoryLabels указывает на одностолбцовый диапазон. Число уровней определяется тем, сколько столбцов охватывает диапазон, а не свойством MultiLevelLable. Укажите многоколоночный диапазон, например A2:B7, и убедитесь, что внешние ячейки подписей объединены в данных.
Шкала вспомогательной оси выглядит неправильно.
Основная и вспомогательная оси значений вычисляют свои шкалы независимо. Установка MinValue или MaxValue в PrimaryValueAxis не влияет на вспомогательную ось. Используйте chart.SecondaryValueAxis, чтобы задать её шкалу напрямую, и делайте это после перемещения ряда на неё.
Ряд роста по-прежнему выглядит плоским после добавления вспомогательной оси.
Проверьте, что UsePrimaryAxis = false задано для ряда роста, а не для ряда продаж. Свойство действует на отдельный ряд — если задать его не тому ряду, на вспомогательную ось переместится не тот ряд.
В легенде отображается "Series 1" вместо имени ряда.
Имя не было передано в Series.Add. Используйте chart.Series.Add({ name: "Sales", ... }), чтобы легенда взяла нужное вам имя, а не автоматически созданную подпись.
Часто задаваемые вопросы
Может ли быть больше двух уровней подписей категорий?
Да. Число уровней определяется количеством столбцов, которые охватывает диапазон CategoryLabels. Диапазон из трёх столбцов даёт три уровня — например, год, квартал и месяц. Внешние ячейки подписей должны быть объединены в данных, чтобы каждый уровень группировался правильно.
Работает ли вспомогательная ось с типами диаграмм, отличными от гистограммы и линейчатой?
Да. Вспомогательная ось не привязана к конкретному типу диаграммы. Распространённый вариант — столбцы плюс линия (линия не занимает ширину столбца и чётко читается на фоне столбцов), но любой ряд можно переместить на вспомогательную ось, задав UsePrimaryAxis = false.
Нужен ли установленный Excel для создания таких диаграмм?
Нет. Движок электронных таблиц поставляется вместе с пакетом и работает как WebAssembly в браузере. Книга полностью создаётся, снабжается диаграммой и сохраняется на стороне клиента.
Можно ли управлять вспомогательной осью категорий отдельно?
Когда ряд перемещается на вспомогательную ось, диаграмма приобретает вспомогательную ось категорий в дополнение к вспомогательной оси значений. По умолчанию обе оси категорий используют одни и те же подписи категорий, поэтому многоуровневые подписи применяются к обеим.
Совместим ли выходной файл с Excel?
Да. Книга сохраняется в формате .xlsx, а диаграмма — включая многоуровневые подписи и вспомогательную ось — записывается в виде стандартного XML диаграмм, который Excel читает изначально.
См. также
Torne os Dados do Excel Visuais com Formatação Condicional em JavaScript
Índice
- Por que não apenas adicionar um gráfico
- Pré-requisitos
- Uma API, três visualizações
- Barras de dados: magnitude em um relance
- Escalas de cores: mapa de calor sem gráfico
- Conjuntos de ícones: faixas de status
- Escolhendo entre os três
- Personalizando a aparência das barras de dados
- Problemas comuns
- Perguntas frequentes
- Veja também

Uma tabela de vendas com vinte colunas de números é precisa e ilegível. O olho não consegue comparar 43.210 com 38.900 ao longo de uma linha rápido o suficiente para encontrar o trimestre fraco, e quem lê o relatório sabe disso — por isso pede um gráfico. Mas um gráfico por coluna significa vinte gráficos, e agora a planilha é uma galeria em vez de uma tabela.
Barras de dados, escalas de cores e conjuntos de ícones resolvem isso dentro das próprias células. Uma barra cresce proporcionalmente ao valor. Uma cor muda de pálida para saturada conforme o número aumenta. Um ícone muda de forma quando o valor cruza um limite. Nenhum deles adiciona linhas, colunas ou objetos flutuantes — a visualização fica na célula que já contém o número. Todos os três são formas de formatação condicional do Excel, e o Spire.XLS for JavaScript os aplica por meio de uma única API no navegador em WebAssembly, com arquivos percorrendo um sistema de arquivos virtual (VFS) e sem necessidade de backend.
Para configuração do projeto, consulte Integrando o Spire.XLS for JavaScript em um projeto React. Os exemplos abaixo assumem que o pacote está instalado e que o módulo WebAssembly foi inicializado.
Por que não apenas adicionar um gráfico
Gráficos e visualização na célula respondem à mesma pergunta — "como esses valores se comparam?" — mas se encaixam em momentos diferentes:
| Gráficos | Visualização na célula | |
|---|---|---|
| Espaço | Flutua sobre a planilha, ocupa uma área retangular | Fica dentro das células que já contêm os dados |
| Densidade | Um gráfico por conjunto de dados; vários gráficos congestionam a planilha | Um formato por intervalo; dezenas de colunas podem exibir indicadores simultaneamente |
| Detalhe | Mostra eixos, linhas de grade, rótulos — uma renderização completa | Mostra apenas o indicador: uma barra, uma cor, um ícone |
| Melhor para | Apresentações, relatórios, exibições isoladas | Escanear uma tabela, identificar valores atípicos, comparar entre muitas colunas |
Quando o objetivo é tornar uma tabela de números fácil de escanear sem reconstruir o layout, a visualização na célula é a ferramenta mais leve. As três seções abaixo cobrem cada tipo, e elas compartilham mais API do que diferem — o que é a primeira coisa que vale a pena saber.
Pré-requisitos
Você precisa de um projeto React com o Spire.XLS for JavaScript instalado e o módulo WebAssembly inicializado, acessível em window.wasmModule.spirexls. O exemplo carrega uma fonte e um arquivo de dados de vendas no VFS, e salva com o sinalizador de versão do Excel 2010, que é a versão mais antiga que suporta esses tipos de formato condicional.
Uma API, três visualizações
Todos os três tipos seguem a mesma cadeia de chamadas. A única linha que muda é a atribuição de FormatType:
sheet.ConditionalFormats.Add() → xcfs.AddRange(range) → format = xcfs.AddCondition() → format.FormatType = ???
| Visualização | Valor de FormatType |
Configuração extra |
|---|---|---|
| Barras de dados | ConditionalFormatType.DataBar |
DataBar.BarColor para a cor de preenchimento |
| Escalas de cores | ConditionalFormatType.ColorScale |
Nenhuma — usa por padrão um gradiente de duas cores |
| Conjuntos de ícones | ConditionalFormatType.IconSet |
IconSet.IconSetType para o estilo do ícone |
A cadeia compartilhada é o motivo pelo qual os três exemplos de código abaixo parecem semelhantes — eles são a mesma operação com um tipo de formato diferente. As diferenças estão no que cada tipo produz e quando você recorreria a ele, o que a tabela de comparação mais adiante neste artigo aborda.
Barras de dados: magnitude em um relance
Uma barra de dados desenha uma faixa colorida horizontal dentro de cada célula, e o comprimento da faixa é proporcional ao valor da célula em relação ao restante do intervalo selecionado. O maior valor preenche a célula; o menor preenche uma lasca. Escanear uma linha de barras de dados é a mesma operação mental que escanear um gráfico de barras, exceto que os números permanecem visíveis por baixo.
Os passos são:
- Carregue a fonte e o arquivo de dados de teste no VFS.
- Carregue a pasta de trabalho e obtenha a planilha.
- Chame
ConditionalFormats.Addpara criar um formato condicional e vincule o intervalo de dados comAddRange. - Chame
AddConditionpara adicionar uma condição, definaFormatTypecomoDataBare defina a cor da barra. - Salve a pasta de trabalho.
function App() {
const applyDataBars = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the data bars
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a data bar condition and set the bar color
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.DataBar;
format.DataBar.BarColor = xlsModule.Color.get_CadetBlue();
// Save the workbook
const outputFileName = "ApplyDataBars.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Data Bars</h1>
<button onClick={applyDataBars}>Start</button>
</div>
);
}
export default App;
Barras de dados aplicadas a uma tabela de números de vendas, com o comprimento da barra proporcional ao valor da célula
![]()
Apenas células numéricas recebem barras — células de texto dentro do intervalo são ignoradas. Isso é esperado: uma barra de dados expressa magnitude relativa, e texto não tem magnitude a expressar. Mantenha o intervalo limitado à área numérica; incluir uma coluna de nomes de produtos ou uma linha de cabeçalho não causa erro, mas essas células não mostrarão nada.
Escalas de cores: mapa de calor sem gráfico
Uma escala de cores sombreia cada célula com base em onde seu valor se posiciona entre o mínimo e o máximo do intervalo. Nenhum argumento de cor é necessário — quando nenhum é especificado, o resultado é uma escala de duas cores que assume laranja no mínimo e amarelo pálido no máximo, com valores intermediários sombreados proporcionalmente. O efeito é um mapa de calor incorporado à tabela de dados: pontos quentes e frios ficam visíveis sem classificação ou gráfico.
Os passos são os mesmos das barras de dados, com FormatType definido como ColorScale e nenhuma propriedade adicional:
- Carregue a fonte e o arquivo de dados de teste no VFS.
- Carregue a pasta de trabalho e obtenha a planilha.
- Chame
ConditionalFormats.Addpara criar um formato condicional e vincule o intervalo de dados comAddRange. - Chame
AddConditionpara adicionar uma condição e definaFormatTypecomoColorScale. - Salve a pasta de trabalho.
function App() {
const applyColorScales = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the color scales
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a color scale condition; colors transition with the values
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.ColorScale;
// Save the workbook
const outputFileName = "ApplyColorScales.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Color Scales</h1>
<button onClick={applyColorScales}>Start</button>
</div>
);
}
export default App;
Escalas de cores aplicadas a uma tabela de números de vendas, com sombreamento de laranja a amarelo pálido
![]()
Enquanto as barras de dados mostram magnitude absoluta por meio do comprimento da barra, as escalas de cores mostram posição relativa por meio da matiz. Um valor no meio do intervalo recebe um tom intermediário independentemente de o intervalo variar de 1 a 100 ou de 10.000 a 50.000 — o sombreamento é posicional, não absoluto.
Conjuntos de ícones: faixas de status
Um conjunto de ícones coloca um ícone diferente em cada célula com base em qual faixa o valor se enquadra. O exemplo usa três semáforos: vermelho para o terço mais baixo, amarelo para o meio, verde para o mais alto. Diferentemente das barras de dados e das escalas de cores, que comunicam um gradiente contínuo, os conjuntos de ícones comunicam uma categoria discreta — "isto é baixo", "isto é médio", "isto é alto" — o que está mais próximo de um indicador de status do que de uma medição.
Os passos diferem apenas no FormatType e na seleção do estilo do ícone:
- Carregue a fonte e o arquivo de dados de teste no VFS.
- Carregue a pasta de trabalho e obtenha a planilha.
- Chame
ConditionalFormats.Addpara criar um formato condicional e vincule o intervalo de dados comAddRange. - Chame
AddConditionpara adicionar uma condição, definaFormatTypecomoIconSete especifique o tipo de conjunto de ícones. - Salve a pasta de trabalho.
function App() {
const applyIconSets = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the icon sets
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add an icon set condition and set the icon style to three traffic lights
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.IconSet;
format.IconSet.IconSetType = xlsModule.IconSetType.ThreeTrafficLights1;
// Save the workbook
const outputFileName = "ApplyIconSets.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Icon Sets</h1>
<button onClick={applyIconSets}>Start</button>
</div>
);
}
export default App;
Conjuntos de ícones aplicados a uma tabela de números de vendas, com ícones de semáforo com base nas faixas de valores
![]()
Um conjunto de ícones divide o intervalo em faixas, portanto o mesmo ícone cobre um intervalo diferente de valores em intervalos diferentes. Em um intervalo de 10 a 90, o ícone verde cobre aproximadamente 60 a 90; em um intervalo de 10 a 900, cobre aproximadamente 600 a 900. As faixas são relativas, não absolutas — o que é o padrão correto para uma tabela em que cada coluna tem sua própria escala, mas vale saber caso você espere um limite fixo.
Escolhendo entre os três
Todos os três são aplicados a um intervalo, todos os três ficam dentro das células e todos os três são formatação condicional. A escolha é sobre o que o leitor precisa fazer com os números:
| O leitor precisa | Use | Porque |
|---|---|---|
| Comparar magnitudes ao longo de uma linha ou coluna | Barras de dados | O comprimento da barra é o indicador visual mais preciso para "quanto" |
| Identificar pontos quentes e frios em uma tabela grande | Escalas de cores | A intensidade da cor é percebida perifericamente mesmo quando o olho não está focado em uma célula específica |
| Classificar valores em algumas categorias de status | Conjuntos de ícones | Ícones discretos mapeiam decisões discretas — "isto precisa de atenção", "isto está bom" |
| Ver tudo o que foi mencionado acima de uma só vez | Combinar em intervalos diferentes | Cada formato condicional é independente; aplique barras de dados a um intervalo e conjuntos de ícones a outro |
Os três não são mutuamente exclusivos. Uma planilha pode conter barras de dados nas colunas de receita e conjuntos de ícones na coluna de taxa de crescimento na mesma gravação, porque cada chamada a ConditionalFormats.Add cria um formato independente vinculado ao seu próprio intervalo.
Personalizando a aparência das barras de dados
A cor de preenchimento de uma barra de dados vem de DataBar.BarColor. Definir apenas FormatType sem BarColor resulta no azul padrão. Uma borda também está disponível, mas tem uma dependência: o tipo de borda deve ser definido antes que a cor da borda entre em vigor.
// Set the border type first so that the border color takes effect
format.DataBar.BarBorder.Type = xlsModule.DataBarBorderType.DataBarBorderSolid;
format.DataBar.BarBorder.Color = xlsModule.Color.get_Red();
// Fill color of the bar
format.DataBar.BarColor = xlsModule.Color.get_GreenYellow();
Definir BarBorder.Color por si só, sem primeiro definir BarBorder.Type, não tem efeito — a borda não é desenhada porque nenhum tipo de borda foi declarado. Escalas de cores e conjuntos de ícones não têm propriedades de aparência equivalentes; seu estilo é determinado pelo tipo de formato e, para conjuntos de ícones, pela enumeração IconSetType.
Problemas comuns
Células de texto no intervalo de destino não mostram barras de dados. Isso é esperado. Uma barra de dados expressa magnitude relativa, e apenas células numéricas têm magnitude. Células de texto são ignoradas silenciosamente — nenhum erro, nenhuma barra. Mantenha o intervalo limitado à área numérica.
As barras de dados estão todas no azul padrão.
DataBar.BarColor não foi definido após a atribuição de FormatType. Defina-o como qualquer valor de xlsModule.Color para alterar o preenchimento.
A cor da borda da barra de dados não está aparecendo.
O tipo de borda não foi definido primeiro. Atribua DataBar.BarBorder.Type antes de DataBar.BarBorder.Color — a cor só entra em vigor depois que um tipo de borda sólida é declarado.
Nenhuma alteração visível após aplicar um formato condicional.
Verifique se o intervalo passado para AddRange corresponde a onde os dados realmente estão. Um intervalo apontando para células vazias não produz erro nem resultado visível.
Perguntas frequentes
Posso aplicar mais de um formato condicional ao mesmo intervalo?
Sim. Cada chamada a ConditionalFormats.Add cria um formato independente. Dois formatos podem ter como alvo o mesmo intervalo, embora o resultado visual de empilhar uma barra de dados e uma escala de cores nas mesmas células possa ser confuso — geralmente é mais claro aplicar tipos diferentes a intervalos diferentes.
Quais versões do Excel suportam esses tipos de formato condicional?
Barras de dados, escalas de cores e conjuntos de ícones foram introduzidos no Excel 2007. O exemplo salva com ExcelVersion.Version2010 para garantir compatibilidade com o Excel 2010 e versões posteriores.
Preciso ter o Excel instalado para aplicar formatação condicional?
Não. O mecanismo de planilha é fornecido com o pacote e é executado como WebAssembly no navegador. A formatação condicional é gravada como XML padrão dentro do arquivo .xlsx, e o Excel a renderiza quando o arquivo é aberto.
Posso definir limites personalizados para conjuntos de ícones?
A enumeração IconSetType seleciona um estilo de ícone predefinido com limites de faixa predefinidos. O exemplo usa ThreeTrafficLights1, que divide o intervalo em três faixas iguais.
A formatação condicional sobrevive se o arquivo for aberto e salvo novamente no Excel?
Sim. A formatação condicional faz parte das regras de formato armazenadas da planilha, não um artefato de renderização. O Excel lê, preserva e reaplica as mesmas regras ao recalcular.
Veja também
JavaScript에서 조건부 서식으로 Excel 데이터 시각화하기

숫자로 가득한 20개 열의 매출 표는 정확하지만 읽을 수가 없습니다. 43,210과 38,900을 한 행에서 비교해 부진한 분기를 찾아내기에는 눈이 너무 느리고, 보고서를 읽는 사람도 이를 알고 있기에 차트를 요청합니다. 하지만 열마다 차트를 만들면 차트가 스무 개가 되고, 워크시트는 표가 아니라 갤러리가 되어 버립니다.
데이터 막대, 색조, 아이콘 집합은 이 문제를 셀 자체 안에서 해결합니다. 막대는 값에 비례해 길어집니다. 숫자가 커질수록 색상은 옅은 색에서 진한 색으로 변합니다. 값이 임계값을 넘으면 아이콘 모양이 바뀝니다. 이들 중 어느 것도 행, 열 또는 떠 있는 개체를 추가하지 않습니다. 시각화는 이미 숫자를 담고 있는 셀 안에 자리합니다. 세 가지 모두 Excel 조건부 서식의 한 형태이며, Spire.XLS for JavaScript는 WebAssembly를 통해 브라우저에서 단일 API로 이를 적용하며, 파일은 가상 파일 시스템(VFS)을 거쳐 이동하고 백엔드가 필요하지 않습니다.
프로젝트 설정은 React 프로젝트에 Spire.XLS for JavaScript 통합하기를 참조하세요. 아래 예제는 패키지가 설치되어 있고 WebAssembly 모듈이 초기화되었다고 가정합니다.
차트를 추가하지 않는 이유
차트와 셀 내 시각화는 같은 질문에 답합니다. 즉, "이 값들은 어떻게 비교되는가?" 하지만 서로 다른 순간에 적합합니다.
| 차트 | 셀 내 시각화 | |
|---|---|---|
| 공간 | 워크시트 위에 떠 있으며 직사각형 영역을 차지함 | 이미 데이터를 담고 있는 셀 안에 존재함 |
| 밀도 | 데이터 집합당 차트 하나이며, 여러 차트는 시트를 복잡하게 만듦 | 범위당 서식 하나이며, 수십 개 열이 동시에 단서를 표시할 수 있음 |
| 세부 정보 | 축, 눈금선, 레이블 등 전체 렌더링을 표시함 | 막대, 색상, 아이콘 등 단서만 표시함 |
| 적합한 용도 | 프레젠테이션, 보고서, 독립형 화면 | 표 훑어보기, 이상값 찾기, 여러 열 간 비교 |
레이아웃을 다시 만들지 않고 숫자 표를 훑어보기 쉽게 만드는 것이 목표라면, 셀 내 시각화가 더 가벼운 도구입니다. 아래 세 섹션에서 각 유형을 다루며, 이들은 차이점보다 공유하는 API가 더 많습니다. 이것이 가장 먼저 알아 둘 만한 점입니다.
사전 요구 사항
Spire.XLS for JavaScript가 설치되고 WebAssembly 모듈이 초기화되어 window.wasmModule.spirexls에서 접근할 수 있는 React 프로젝트가 필요합니다. 샘플은 폰트와 매출 데이터 파일을 VFS에 로드하고, 이러한 조건부 서식 유형을 지원하는 가장 이른 버전인 Excel 2010 버전 플래그로 저장합니다.
하나의 API, 세 가지 시각화
세 가지 유형 모두 동일한 호출 체인을 따릅니다. 바뀌는 줄은 FormatType 할당뿐입니다.
sheet.ConditionalFormats.Add() → xcfs.AddRange(range) → format = xcfs.AddCondition() → format.FormatType = ???
| 시각화 | FormatType 값 |
추가 설정 |
|---|---|---|
| 데이터 막대 | ConditionalFormatType.DataBar |
채우기 색상은 DataBar.BarColor |
| 색조 | ConditionalFormatType.ColorScale |
없음 — 기본값은 두 색 그라데이션 |
| 아이콘 집합 | ConditionalFormatType.IconSet |
아이콘 스타일은 IconSet.IconSetType |
공유된 호출 체인 때문에 아래 세 코드 예제는 비슷해 보입니다. 이들은 서로 다른 서식 유형을 가진 동일한 작업입니다. 차이는 각 유형이 만들어 내는 결과와 언제 이를 선택하게 되는지에 있으며, 이 문서 뒷부분의 비교 표에서 다룹니다.
데이터 막대: 한눈에 보는 크기
데이터 막대는 각 셀 안에 가로 방향의 색 띠를 그리며, 띠의 길이는 선택한 범위의 나머지 값 대비 해당 셀 값에 비례합니다. 가장 큰 값은 셀을 가득 채우고, 가장 작은 값은 가느다란 조각만 채웁니다. 데이터 막대 행을 훑어보는 것은 막대 차트를 훑어보는 것과 같은 정신적 작업이며, 다만 숫자가 아래에 그대로 보입니다.
단계는 다음과 같습니다.
- 폰트와 테스트 데이터 파일을 VFS에 로드합니다.
- 통합 문서를 로드하고 워크시트를 가져옵니다.
ConditionalFormats.Add를 호출해 조건부 서식을 만들고,AddRange로 데이터 범위를 바인딩합니다.AddCondition을 호출해 조건을 추가하고,FormatType을DataBar로 설정한 뒤 막대 색상을 설정합니다.- 통합 문서를 저장합니다.
function App() {
const applyDataBars = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the data bars
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a data bar condition and set the bar color
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.DataBar;
format.DataBar.BarColor = xlsModule.Color.get_CadetBlue();
// Save the workbook
const outputFileName = "ApplyDataBars.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Data Bars</h1>
<button onClick={applyDataBars}>Start</button>
</div>
);
}
export default App;
매출 수치 표에 적용된 데이터 막대, 막대 길이는 셀 값에 비례함
![]()
숫자 셀만 막대를 받으며, 범위 내의 텍스트 셀은 건너뜁니다. 이는 예상된 동작입니다. 데이터 막대는 상대적 크기를 표현하는데, 텍스트에는 표현할 크기가 없습니다. 범위는 숫자 영역으로 한정하세요. 제품명 열이나 머리글 행을 포함해도 오류는 발생하지 않지만, 해당 셀에는 아무것도 표시되지 않습니다.
색조: 차트 없는 히트맵
색조는 범위의 최솟값과 최댓값 사이에서 해당 값의 위치에 따라 각 셀에 음영을 입힙니다. 색상 인수를 지정할 필요가 없습니다. 아무것도 지정하지 않으면 최솟값에 주황색, 최댓값에 옅은 노란색을 취하고 중간 값은 비례적으로 음영 처리되는 두 색 스케일이 결과로 나옵니다. 그 효과는 데이터 표에 내장된 히트맵으로, 정렬이나 차트 없이도 뜨거운 지점과 차가운 지점이 보입니다.
단계는 데이터 막대와 동일하며, FormatType을 ColorScale로 설정하고 추가 속성이 없습니다.
- 폰트와 테스트 데이터 파일을 VFS에 로드합니다.
- 통합 문서를 로드하고 워크시트를 가져옵니다.
ConditionalFormats.Add를 호출해 조건부 서식을 만들고,AddRange로 데이터 범위를 바인딩합니다.AddCondition을 호출해 조건을 추가하고,FormatType을ColorScale로 설정합니다.- 통합 문서를 저장합니다.
function App() {
const applyColorScales = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the color scales
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a color scale condition; colors transition with the values
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.ColorScale;
// Save the workbook
const outputFileName = "ApplyColorScales.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Color Scales</h1>
<button onClick={applyColorScales}>Start</button>
</div>
);
}
export default App;
매출 수치 표에 적용된 색조, 주황색에서 옅은 노란색으로 이어지는 음영
![]()
데이터 막대가 막대 길이를 통해 절대적 크기를 보여 준다면, 색조는 색상을 통해 상대적 위치를 보여 줍니다. 범위가 1에서 100이든 10,000에서 50,000이든 중간 값은 중간 색조를 받습니다. 즉 음영은 절대적이 아니라 위치에 기반합니다.
아이콘 집합: 상태 구간
아이콘 집합은 값이 어느 구간에 속하는지에 따라 각 셀에 서로 다른 아이콘을 배치합니다. 예제는 세 가지 신호등을 사용합니다. 가장 낮은 3분의 1에는 빨간색, 중간에는 노란색, 가장 높은 값에는 초록색입니다. 연속적인 그라데이션을 전달하는 데이터 막대와 색조와 달리, 아이콘 집합은 이산적인 범주, 즉 "이것은 낮음", "이것은 중간", "이것은 높음"을 전달하며, 이는 측정값이라기보다 상태 표시에 가깝습니다.
단계는 FormatType과 아이콘 스타일 선택에서만 다릅니다.
- 폰트와 테스트 데이터 파일을 VFS에 로드합니다.
- 통합 문서를 로드하고 워크시트를 가져옵니다.
ConditionalFormats.Add를 호출해 조건부 서식을 만들고,AddRange로 데이터 범위를 바인딩합니다.AddCondition을 호출해 조건을 추가하고,FormatType을IconSet으로 설정한 뒤 아이콘 집합 유형을 지정합니다.- 통합 문서를 저장합니다.
function App() {
const applyIconSets = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the icon sets
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add an icon set condition and set the icon style to three traffic lights
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.IconSet;
format.IconSet.IconSetType = xlsModule.IconSetType.ThreeTrafficLights1;
// Save the workbook
const outputFileName = "ApplyIconSets.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Icon Sets</h1>
<button onClick={applyIconSets}>Start</button>
</div>
);
}
export default App;
매출 수치 표에 적용된 아이콘 집합, 값 구간에 따른 신호등 아이콘
![]()
아이콘 집합은 범위를 구간으로 나누므로, 같은 아이콘이 범위에 따라 서로 다른 값 범위를 담당합니다. 10에서 90 범위에서는 초록색 아이콘이 대략 60에서 90을 담당하고, 10에서 900 범위에서는 대략 600에서 900을 담당합니다. 구간은 절대적이지 않고 상대적입니다. 이는 각 열이 고유한 척도를 가지는 표에 적합한 기본값이지만, 고정 임계값을 기대한다면 알아 둘 만합니다.
세 가지 중에서 선택하기
세 가지 모두 범위에 적용되고, 모두 셀 안에 존재하며, 모두 조건부 서식입니다. 선택은 읽는 사람이 숫자로 무엇을 해야 하는지에 달려 있습니다.
| 읽는 사람이 해야 하는 일 | 사용 | 이유 |
|---|---|---|
| 행이나 열 전체에서 크기 비교 | 데이터 막대 | 막대 길이는 "얼마나 많은가"에 대한 가장 정밀한 시각적 단서임 |
| 큰 표에서 뜨거운 지점과 차가운 지점 찾기 | 색조 | 색상 강도는 시선이 특정 셀에 집중하지 않아도 주변부에서 인지됨 |
| 값을 몇 가지 상태 범주로 분류 | 아이콘 집합 | 이산적인 아이콘은 "주의 필요", "양호" 같은 이산적인 판단에 대응함 |
| 위의 모든 것을 한 번에 보기 | 서로 다른 범위에 조합 | 각 조건부 서식은 독립적이므로, 한 범위에는 데이터 막대를, 다른 범위에는 아이콘 집합을 적용할 수 있음 |
세 가지는 상호 배타적이지 않습니다. 각 ConditionalFormats.Add 호출은 자체 범위에 바인딩된 독립적인 서식을 만들기 때문에, 한 번의 저장으로 매출 열에는 데이터 막대를, 성장률 열에는 아이콘 집합을 적용할 수 있습니다.
데이터 막대 모양 사용자 지정
데이터 막대의 채우기 색상은 DataBar.BarColor에서 옵니다. BarColor 없이 FormatType만 설정하면 기본 파란색이 됩니다. 테두리도 사용할 수 있지만 의존성이 있습니다. 테두리 색상이 적용되려면 테두리 유형을 먼저 설정해야 합니다.
// Set the border type first so that the border color takes effect
format.DataBar.BarBorder.Type = xlsModule.DataBarBorderType.DataBarBorderSolid;
format.DataBar.BarBorder.Color = xlsModule.Color.get_Red();
// Fill color of the bar
format.DataBar.BarColor = xlsModule.Color.get_GreenYellow();
BarBorder.Type을 먼저 설정하지 않고 BarBorder.Color만 설정하면 아무 효과가 없습니다. 테두리 유형이 선언되지 않았으므로 테두리가 그려지지 않습니다. 색조와 아이콘 집합에는 이에 상응하는 모양 속성이 없습니다. 이들의 스타일은 서식 유형에 의해 결정되며, 아이콘 집합의 경우 IconSetType 열거형에 의해 결정됩니다.
일반적인 문제
대상 범위의 텍스트 셀에 데이터 막대가 표시되지 않습니다. 이는 예상된 동작입니다. 데이터 막대는 상대적 크기를 표현하며, 숫자 셀만 크기를 가집니다. 텍스트 셀은 오류도, 막대도 없이 조용히 건너뜁니다. 범위를 숫자 영역으로 제한하세요.
데이터 막대가 모두 기본 파란색입니다.
FormatType을 할당한 뒤 DataBar.BarColor를 설정하지 않았습니다. 채우기를 변경하려면 임의의 xlsModule.Color 값으로 설정하세요.
데이터 막대 테두리 색상이 표시되지 않습니다.
테두리 유형을 먼저 설정하지 않았습니다. DataBar.BarBorder.Color보다 DataBar.BarBorder.Type을 먼저 할당하세요. 실선 테두리 유형이 선언되어야 색상이 적용됩니다.
조건부 서식을 적용한 후에도 눈에 띄는 변화가 없습니다.
AddRange에 전달한 범위가 실제 데이터가 있는 위치와 일치하는지 확인하세요. 빈 셀을 가리키는 범위는 오류도, 눈에 보이는 결과도 만들어 내지 않습니다.
자주 묻는 질문
같은 범위에 조건부 서식을 두 개 이상 적용할 수 있나요?
예. ConditionalFormats.Add를 호출할 때마다 독립적인 서식이 만들어집니다. 두 서식이 같은 범위를 대상으로 할 수 있지만, 같은 셀에 데이터 막대와 색조를 겹쳐 놓으면 시각적 결과가 혼란스러울 수 있으므로 일반적으로는 서로 다른 유형을 서로 다른 범위에 적용하는 편이 더 명확합니다.
이러한 조건부 서식 유형을 지원하는 Excel 버전은 무엇인가요?
데이터 막대, 색조, 아이콘 집합은 Excel 2007에서 도입되었습니다. 샘플은 Excel 2010 및 이후 버전과의 호환성을 보장하기 위해 ExcelVersion.Version2010으로 저장합니다.
조건부 서식을 적용하려면 Excel이 설치되어 있어야 하나요?
아니요. 스프레드시트 엔진은 패키지에 포함되어 브라우저에서 WebAssembly로 실행됩니다. 조건부 서식은 .xlsx 파일 내부에 표준 XML로 기록되며, Excel은 파일을 열 때 이를 렌더링합니다.
아이콘 집합에 사용자 지정 임계값을 설정할 수 있나요?
IconSetType 열거형은 미리 정의된 구간 경계를 가진 미리 정의된 아이콘 스타일을 선택합니다. 예제는 범위를 세 개의 동일한 구간으로 나누는 ThreeTrafficLights1을 사용합니다.
Excel에서 파일을 열고 다시 저장해도 조건부 서식이 유지되나요?
예. 조건부 서식은 렌더링 결과물이 아니라 워크시트에 저장된 서식 규칙의 일부입니다. Excel은 동일한 규칙을 읽고, 보존하며, 다시 계산할 때 다시 적용합니다.
함께 보기
Rendi visivi i dati di Excel con la formattazione condizionale in JavaScript
Indice
- Perché non aggiungere semplicemente un grafico
- Prerequisiti
- Un'unica API, tre visualizzazioni
- Barre dei dati: la grandezza a colpo d'occhio
- Scale di colori: mappe di calore senza grafico
- Set di icone: fasce di stato
- Scegliere tra i tre
- Personalizzare l'aspetto delle barre dei dati
- Problemi comuni
- FAQ
- Vedi anche

Una tabella di vendite con venti colonne di numeri è accurata e illeggibile. L'occhio non riesce a confrontare 43.210 con 38.900 lungo una riga abbastanza velocemente da individuare il trimestre debole, e chi legge il report lo sa — ed è per questo che chiede un grafico. Ma un grafico per colonna significa venti grafici, e ora il foglio di lavoro è una galleria invece di una tabella.
Le barre dei dati, le scale di colori e i set di icone risolvono il problema all'interno delle celle stesse. Una barra cresce in proporzione al valore. Un colore passa dal tenue al saturo man mano che il numero aumenta. Un'icona cambia forma quando il valore supera una soglia. Nessuno di essi aggiunge righe, colonne o oggetti fluttuanti — la visualizzazione risiede nella cella che già contiene il numero. Tutti e tre sono forme di formattazione condizionale di Excel, e Spire.XLS for JavaScript le applica tramite un'unica API nel browser su WebAssembly, con i file che passano attraverso un file system virtuale (VFS) e senza necessità di un backend.
Per la configurazione del progetto, vedi Integrare Spire.XLS for JavaScript in un progetto React. Gli esempi seguenti presuppongono che il pacchetto sia installato e che il modulo WebAssembly sia stato inizializzato.
Perché non aggiungere semplicemente un grafico
I grafici e la visualizzazione all'interno delle celle rispondono alla stessa domanda — "come si confrontano questi valori?" — ma si adattano a momenti diversi:
| Grafici | Visualizzazione nelle celle | |
|---|---|---|
| Spazio | Fluttua sopra il foglio di lavoro, occupa un'area rettangolare | Vive all'interno delle celle che già contengono i dati |
| Densità | Un grafico per set di dati; più grafici affollano il foglio | Un formato per intervallo; decine di colonne possono veicolare indicazioni contemporaneamente |
| Dettaglio | Mostra assi, linee della griglia, etichette — una resa completa | Mostra solo l'indicazione: una barra, un colore, un'icona |
| Ideale per | Presentazioni, report, visualizzazioni autonome | Scansionare una tabella, individuare valori anomali, confrontare molte colonne |
Quando l'obiettivo è rendere leggibile a colpo d'occhio una tabella di numeri senza ricostruire il layout, la visualizzazione nelle celle è lo strumento più leggero. Le tre sezioni seguenti trattano ciascun tipo, e condividono più API di quante ne differenzino — ed è la prima cosa che vale la pena sapere.
Prerequisiti
Serve un progetto React con Spire.XLS for JavaScript installato e il modulo WebAssembly inizializzato, accessibile all'indirizzo window.wasmModule.spirexls. L'esempio carica un font e un file di dati di vendita nel VFS e salva con il flag della versione Excel 2010, che è la prima versione a supportare questi tipi di formato condizionale.
Un'unica API, tre visualizzazioni
Tutti e tre i tipi seguono la stessa catena di chiamate. L'unica riga che cambia è l'assegnazione di FormatType:
sheet.ConditionalFormats.Add() → xcfs.AddRange(range) → format = xcfs.AddCondition() → format.FormatType = ???
| Visualizzazione | Valore FormatType |
Configurazione aggiuntiva |
|---|---|---|
| Barre dei dati | ConditionalFormatType.DataBar |
DataBar.BarColor per il colore di riempimento |
| Scale di colori | ConditionalFormatType.ColorScale |
Nessuna — per impostazione predefinita usa una sfumatura a due colori |
| Set di icone | ConditionalFormatType.IconSet |
IconSet.IconSetType per lo stile dell'icona |
La catena condivisa è il motivo per cui i tre esempi di codice seguenti si assomigliano — sono la stessa operazione con un tipo di formato diverso. Le differenze stanno in ciò che ciascun tipo produce e in quando lo si utilizzerebbe, ed è proprio questo che affronta la tabella di confronto più avanti nell'articolo.
Barre dei dati: la grandezza a colpo d'occhio
Una barra dei dati disegna una fascia colorata orizzontale all'interno di ogni cella, e la lunghezza della fascia è proporzionale al valore della cella rispetto al resto dell'intervallo selezionato. Il valore più grande riempie la cella; il più piccolo riempie uno spicchio sottile. Scansionare una riga di barre dei dati è la stessa operazione mentale che scansionare un grafico a barre, con la differenza che i numeri restano visibili sotto.
I passaggi sono:
- Caricare il font e il file di dati di test nel VFS.
- Caricare la cartella di lavoro e ottenere il foglio di lavoro.
- Chiamare
ConditionalFormats.Addper creare un formato condizionale e associare l'intervallo di dati conAddRange. - Chiamare
AddConditionper aggiungere una condizione, impostareFormatTypesuDataBare impostare il colore della barra. - Salvare la cartella di lavoro.
function App() {
const applyDataBars = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the data bars
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a data bar condition and set the bar color
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.DataBar;
format.DataBar.BarColor = xlsModule.Color.get_CadetBlue();
// Save the workbook
const outputFileName = "ApplyDataBars.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Data Bars</h1>
<button onClick={applyDataBars}>Start</button>
</div>
);
}
export default App;
Barre dei dati applicate a una tabella di cifre di vendita, lunghezza della barra proporzionale al valore della cella
![]()
Solo le celle numeriche ricevono le barre — le celle di testo all'interno dell'intervallo vengono ignorate. È il comportamento previsto: una barra dei dati esprime una grandezza relativa, e il testo non ha alcuna grandezza da esprimere. Mantieni l'intervallo delimitato all'area numerica; includere una colonna con i nomi dei prodotti o una riga di intestazione non causa un errore, ma quelle celle non mostreranno nulla.
Scale di colori: mappe di calore senza grafico
Una scala di colori ombreggia ogni cella in base alla posizione del suo valore tra il minimo e il massimo dell'intervallo. Non sono richiesti argomenti di colore — quando non ne viene specificato nessuno, il risultato è una scala a due colori che assume l'arancione in corrispondenza del minimo e il giallo pallido in corrispondenza del massimo, con i valori intermedi ombreggiati in proporzione. L'effetto è una mappa di calore incorporata nella tabella di dati: i punti caldi e quelli freddi sono visibili senza ordinare né creare grafici.
I passaggi sono gli stessi delle barre dei dati, con FormatType impostato su ColorScale e nessuna proprietà aggiuntiva:
- Caricare il font e il file di dati di test nel VFS.
- Caricare la cartella di lavoro e ottenere il foglio di lavoro.
- Chiamare
ConditionalFormats.Addper creare un formato condizionale e associare l'intervallo di dati conAddRange. - Chiamare
AddConditionper aggiungere una condizione e impostareFormatTypesuColorScale. - Salvare la cartella di lavoro.
function App() {
const applyColorScales = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the color scales
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a color scale condition; colors transition with the values
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.ColorScale;
// Save the workbook
const outputFileName = "ApplyColorScales.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Color Scales</h1>
<button onClick={applyColorScales}>Start</button>
</div>
);
}
export default App;
Scale di colori applicate a una tabella di cifre di vendita, con ombreggiatura dall'arancione al giallo pallido
![]()
Mentre le barre dei dati mostrano la grandezza assoluta attraverso la lunghezza della barra, le scale di colori mostrano la posizione relativa attraverso la tonalità. Un valore al centro dell'intervallo ottiene una tonalità intermedia indipendentemente dal fatto che l'intervallo vada da 1 a 100 o da 10.000 a 50.000 — l'ombreggiatura è posizionale, non assoluta.
Set di icone: fasce di stato
Un set di icone colloca un'icona diversa in ogni cella in base alla fascia in cui ricade il valore. L'esempio utilizza i tre semafori: rosso per il terzo più basso, giallo per quello intermedio, verde per il più alto. A differenza delle barre dei dati e delle scale di colori, che comunicano un gradiente continuo, i set di icone comunicano una categoria discreta — "questo è basso", "questo è medio", "questo è alto" — il che è più vicino a un indicatore di stato che a una misurazione.
I passaggi differiscono solo per FormatType e per la selezione dello stile dell'icona:
- Caricare il font e il file di dati di test nel VFS.
- Caricare la cartella di lavoro e ottenere il foglio di lavoro.
- Chiamare
ConditionalFormats.Addper creare un formato condizionale e associare l'intervallo di dati conAddRange. - Chiamare
AddConditionper aggiungere una condizione, impostareFormatTypesuIconSete specificare il tipo di set di icone. - Salvare la cartella di lavoro.
function App() {
const applyIconSets = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the icon sets
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add an icon set condition and set the icon style to three traffic lights
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.IconSet;
format.IconSet.IconSetType = xlsModule.IconSetType.ThreeTrafficLights1;
// Save the workbook
const outputFileName = "ApplyIconSets.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Icon Sets</h1>
<button onClick={applyIconSets}>Start</button>
</div>
);
}
export default App;
Set di icone applicati a una tabella di cifre di vendita, icone a semaforo basate sulle fasce di valore
![]()
Un set di icone divide l'intervallo in fasce, quindi la stessa icona copre un intervallo di valori diverso in intervalli diversi. In un intervallo da 10 a 90, l'icona verde copre all'incirca da 60 a 90; in un intervallo da 10 a 900, copre all'incirca da 600 a 900. Le fasce sono relative, non assolute — il che è l'impostazione predefinita corretta per una tabella in cui ogni colonna ha la propria scala, ma vale la pena saperlo se ci si aspetta una soglia fissa.
Scegliere tra i tre
Tutti e tre vengono applicati a un intervallo, tutti e tre risiedono all'interno delle celle e tutti e tre sono formattazione condizionale. La scelta riguarda ciò che il lettore deve fare con i numeri:
| Il lettore deve | Usare | Perché |
|---|---|---|
| Confrontare grandezze lungo una riga o una colonna | Barre dei dati | La lunghezza della barra è l'indizio visivo più preciso per "quanto" |
| Individuare punti caldi e freddi in una tabella grande | Scale di colori | L'intensità del colore viene percepita perifericamente anche quando l'occhio non è concentrato su una cella specifica |
| Classificare i valori in poche categorie di stato | Set di icone | Icone discrete corrispondono a decisioni discrete — "questo richiede attenzione", "questo va bene" |
| Vedere tutto quanto sopra contemporaneamente | Combinare su intervalli diversi | Ogni formato condizionale è indipendente; applica le barre dei dati a un intervallo e i set di icone a un altro |
I tre non si escludono a vicenda. Un foglio di lavoro può contenere barre dei dati sulle colonne dei ricavi e set di icone sulla colonna del tasso di crescita nello stesso salvataggio, perché ogni chiamata a ConditionalFormats.Add crea un formato indipendente associato al proprio intervallo.
Personalizzare l'aspetto delle barre dei dati
Il colore di riempimento di una barra dei dati proviene da DataBar.BarColor. Impostando solo FormatType senza BarColor si ottiene il blu predefinito. È disponibile anche un bordo, ma ha una dipendenza: il tipo di bordo deve essere impostato prima che il colore del bordo abbia effetto.
// Set the border type first so that the border color takes effect
format.DataBar.BarBorder.Type = xlsModule.DataBarBorderType.DataBarBorderSolid;
format.DataBar.BarBorder.Color = xlsModule.Color.get_Red();
// Fill color of the bar
format.DataBar.BarColor = xlsModule.Color.get_GreenYellow();
Impostare BarBorder.Color da solo, senza impostare prima BarBorder.Type, non ha alcun effetto — il bordo non viene disegnato perché non è stato dichiarato alcun tipo di bordo. Le scale di colori e i set di icone non hanno proprietà equivalenti di aspetto; il loro stile è determinato dal tipo di formato e, per i set di icone, dall'enumerazione IconSetType.
Problemi comuni
Le celle di testo nell'intervallo di destinazione non mostrano barre dei dati. Questo è il comportamento previsto. Una barra dei dati esprime una grandezza relativa, e solo le celle numeriche hanno una grandezza. Le celle di testo vengono ignorate silenziosamente — nessun errore, nessuna barra. Mantieni l'intervallo limitato all'area numerica.
Le barre dei dati sono tutte del blu predefinito.
DataBar.BarColor non è stato impostato dopo l'assegnazione di FormatType. Impostalo su un qualsiasi valore di xlsModule.Color per cambiare il riempimento.
Il colore del bordo delle barre dei dati non viene visualizzato.
Il tipo di bordo non è stato impostato per primo. Assegna DataBar.BarBorder.Type prima di DataBar.BarBorder.Color — il colore ha effetto solo dopo che è stato dichiarato un tipo di bordo pieno.
Nessun cambiamento visibile dopo l'applicazione di un formato condizionale.
Verifica che l'intervallo passato a AddRange corrisponda a dove si trovano effettivamente i dati. Un intervallo che punta a celle vuote non produce errori né risultati visibili.
FAQ
Posso applicare più di un formato condizionale allo stesso intervallo?
Sì. Ogni chiamata a ConditionalFormats.Add crea un formato indipendente. Due formati possono avere come destinazione lo stesso intervallo, anche se il risultato visivo di sovrapporre una barra dei dati e una scala di colori sulle stesse celle può risultare confuso — di solito è più chiaro applicare tipi diversi a intervalli diversi.
Quali versioni di Excel supportano questi tipi di formato condizionale?
Le barre dei dati, le scale di colori e i set di icone sono stati introdotti in Excel 2007. L'esempio salva con ExcelVersion.Version2010 per garantire la compatibilità sia con Excel 2010 sia con le versioni successive.
Serve Excel installato per applicare la formattazione condizionale?
No. Il motore per fogli di calcolo è incluso nel pacchetto e viene eseguito come WebAssembly nel browser. La formattazione condizionale viene scritta come XML standard all'interno del file .xlsx, ed Excel la renderizza all'apertura del file.
Posso impostare soglie personalizzate per i set di icone?
L'enumerazione IconSetType seleziona uno stile di icona predefinito con confini di fascia predefiniti. L'esempio usa ThreeTrafficLights1, che divide l'intervallo in tre fasce uguali.
La formattazione condizionale sopravvive se il file viene aperto e salvato di nuovo in Excel?
Sì. La formattazione condizionale fa parte delle regole di formato memorizzate nel foglio di lavoro, non è un artefatto di rendering. Excel legge, preserva e riapplica le stesse regole al ricalcolo.
Vedi anche
Rendre les données Excel visuelles avec la mise en forme conditionnelle en JavaScript
Table des matières
- Pourquoi ne pas simplement ajouter un graphique
- Prérequis
- Une seule API, trois visualisations
- Barres de données : l'ampleur en un coup d'œil
- Échelles de couleurs : cartographie thermique sans graphique
- Jeux d'icônes : bandes de statut
- Choisir entre les trois
- Personnaliser l'apparence des barres de données
- Problèmes courants
- FAQ
- Voir aussi

Un tableau de ventes comportant vingt colonnes de chiffres est exact et illisible. L'œil ne peut pas comparer 43 210 à 38 900 sur une ligne assez rapidement pour repérer le trimestre faible, et la personne qui lit le rapport le sait — c'est pourquoi elle demande un graphique. Mais un graphique par colonne signifie vingt graphiques, et la feuille de calcul devient une galerie plutôt qu'un tableau.
Les barres de données, les échelles de couleurs et les jeux d'icônes résolvent ce problème à l'intérieur même des cellules. Une barre s'allonge proportionnellement à la valeur. Une couleur passe du pâle au saturé à mesure que le nombre augmente. Une icône change de forme lorsque la valeur franchit un seuil. Aucun d'eux n'ajoute de lignes, de colonnes ou d'objets flottants — la visualisation se trouve dans la cellule qui contient déjà le nombre. Tous trois sont des formes de mise en forme conditionnelle Excel, et Spire.XLS for JavaScript les applique via une API unique dans le navigateur sur WebAssembly, les fichiers circulant dans un système de fichiers virtuel (VFS) et sans nécessiter de backend.
Pour la configuration du projet, consultez Intégrer Spire.XLS for JavaScript dans un projet React. Les exemples ci-dessous supposent que le paquet est installé et que le module WebAssembly a été initialisé.
Pourquoi ne pas simplement ajouter un graphique
Les graphiques et la visualisation dans les cellules répondent à la même question — "comment ces valeurs se comparent-elles ?" — mais ils conviennent à des moments différents :
| Graphiques | Visualisation dans les cellules | |
|---|---|---|
| Espace | Flotte au-dessus de la feuille de calcul, occupe une zone rectangulaire | Réside à l'intérieur des cellules qui contiennent déjà les données |
| Densité | Un graphique par jeu de données ; plusieurs graphiques encombrent la feuille | Un format par plage ; des dizaines de colonnes peuvent porter des repères simultanément |
| Détail | Affiche les axes, le quadrillage, les étiquettes — un rendu complet | Affiche uniquement le repère : une barre, une couleur, une icône |
| Idéal pour | Les présentations, les rapports, les affichages autonomes | Parcourir un tableau, repérer les valeurs aberrantes, comparer sur de nombreuses colonnes |
Lorsque l'objectif est de rendre un tableau de chiffres facile à parcourir sans reconstruire la mise en page, la visualisation dans les cellules est l'outil le plus léger. Les trois sections ci-dessous couvrent chaque type, et ils partagent plus d'API qu'ils n'en diffèrent — ce qui est la première chose à savoir.
Prérequis
Vous avez besoin d'un projet React avec Spire.XLS for JavaScript installé et le module WebAssembly initialisé, accessible à window.wasmModule.spirexls. L'exemple charge une police et un fichier de données de ventes dans le VFS, et enregistre avec l'indicateur de version Excel 2010, qui est la version la plus ancienne prenant en charge ces types de mise en forme conditionnelle.
Une seule API, trois visualisations
Les trois types suivent la même chaîne d'appels. La seule ligne qui change est l'attribution de FormatType :
sheet.ConditionalFormats.Add() → xcfs.AddRange(range) → format = xcfs.AddCondition() → format.FormatType = ???
| Visualisation | Valeur de FormatType |
Configuration supplémentaire |
|---|---|---|
| Barres de données | ConditionalFormatType.DataBar |
DataBar.BarColor pour la couleur de remplissage |
| Échelles de couleurs | ConditionalFormatType.ColorScale |
Aucune — utilise par défaut un dégradé à deux couleurs |
| Jeux d'icônes | ConditionalFormatType.IconSet |
IconSet.IconSetType pour le style d'icône |
C'est cette chaîne commune qui explique la ressemblance des trois exemples de code ci-dessous — il s'agit de la même opération avec un type de format différent. Les différences résident dans ce que chaque type produit et dans le moment où vous y feriez appel, ce que le tableau comparatif plus loin dans cet article aborde.
Barres de données : l'ampleur en un coup d'œil
Une barre de données dessine une bande colorée horizontale à l'intérieur de chaque cellule, et la longueur de la bande est proportionnelle à la valeur de la cellule par rapport au reste de la plage sélectionnée. La valeur la plus élevée remplit la cellule ; la plus faible n'en remplit qu'un filet. Parcourir une ligne de barres de données est la même opération mentale que parcourir un graphique à barres, à ceci près que les chiffres restent visibles en dessous.
Les étapes sont les suivantes :
- Chargez la police et le fichier de données de test dans le VFS.
- Chargez le classeur et récupérez la feuille de calcul.
- Appelez
ConditionalFormats.Addpour créer une mise en forme conditionnelle, et liez la plage de données avecAddRange. - Appelez
AddConditionpour ajouter une condition, définissezFormatTypesurDataBaret définissez la couleur de la barre. - Enregistrez le classeur.
function App() {
const applyDataBars = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the data bars
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a data bar condition and set the bar color
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.DataBar;
format.DataBar.BarColor = xlsModule.Color.get_CadetBlue();
// Save the workbook
const outputFileName = "ApplyDataBars.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Data Bars</h1>
<button onClick={applyDataBars}>Start</button>
</div>
);
}
export default App;
Barres de données appliquées à un tableau de chiffres de ventes, longueur de barre proportionnelle à la valeur de la cellule
![]()
Seules les cellules numériques reçoivent des barres — les cellules de texte à l'intérieur de la plage sont ignorées. C'est normal : une barre de données exprime une magnitude relative, et le texte n'a pas de magnitude à exprimer. Gardez la plage délimitée par la zone numérique ; inclure une colonne de noms de produits ou une ligne d'en-tête ne provoque pas d'erreur, mais ces cellules n'afficheront rien.
Échelles de couleurs : cartographie thermique sans graphique
Une échelle de couleurs ombre chaque cellule en fonction de la position de sa valeur entre le minimum et le maximum de la plage. Aucun argument de couleur n'est requis — lorsqu'aucun n'est spécifié, le résultat est une échelle à deux couleurs qui prend l'orange au minimum et le jaune pâle au maximum, les valeurs intermédiaires étant ombrées proportionnellement. L'effet est une carte thermique intégrée au tableau de données : les points chauds et les points froids sont visibles sans tri ni graphique.
Les étapes sont les mêmes que pour les barres de données, avec FormatType défini sur ColorScale et aucune propriété supplémentaire :
- Chargez la police et le fichier de données de test dans le VFS.
- Chargez le classeur et récupérez la feuille de calcul.
- Appelez
ConditionalFormats.Addpour créer une mise en forme conditionnelle, et liez la plage de données avecAddRange. - Appelez
AddConditionpour ajouter une condition, et définissezFormatTypesurColorScale. - Enregistrez le classeur.
function App() {
const applyColorScales = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the color scales
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a color scale condition; colors transition with the values
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.ColorScale;
// Save the workbook
const outputFileName = "ApplyColorScales.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Color Scales</h1>
<button onClick={applyColorScales}>Start</button>
</div>
);
}
export default App;
Échelles de couleurs appliquées à un tableau de chiffres de ventes, dégradé de l'orange au jaune pâle
![]()
Là où les barres de données montrent la magnitude absolue par la longueur de la barre, les échelles de couleurs montrent la position relative par la teinte. Une valeur au milieu de la plage obtient une teinte intermédiaire, que la plage s'étende de 1 à 100 ou de 10 000 à 50 000 — l'ombrage est positionnel, non absolu.
Jeux d'icônes : bandes de statut
Un jeu d'icônes place une icône différente dans chaque cellule selon la bande dans laquelle tombe la valeur. L'exemple utilise des feux tricolores : rouge pour le tiers le plus bas, jaune pour le milieu, vert pour le plus élevé. Contrairement aux barres de données et aux échelles de couleurs, qui communiquent un dégradé continu, les jeux d'icônes communiquent une catégorie discrète — "c'est faible", "c'est moyen", "c'est élevé" — ce qui se rapproche davantage d'un indicateur de statut que d'une mesure.
Les étapes ne diffèrent que par le FormatType et la sélection du style d'icône :
- Chargez la police et le fichier de données de test dans le VFS.
- Chargez le classeur et récupérez la feuille de calcul.
- Appelez
ConditionalFormats.Addpour créer une mise en forme conditionnelle, et liez la plage de données avecAddRange. - Appelez
AddConditionpour ajouter une condition, définissezFormatTypesurIconSetet spécifiez le type de jeu d'icônes. - Enregistrez le classeur.
function App() {
const applyIconSets = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the icon sets
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add an icon set condition and set the icon style to three traffic lights
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.IconSet;
format.IconSet.IconSetType = xlsModule.IconSetType.ThreeTrafficLights1;
// Save the workbook
const outputFileName = "ApplyIconSets.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Apply Icon Sets</h1>
<button onClick={applyIconSets}>Start</button>
</div>
);
}
export default App;
Jeux d'icônes appliqués à un tableau de chiffres de ventes, icônes de feux tricolores basées sur des bandes de valeurs
![]()
Un jeu d'icônes divise la plage en bandes, de sorte que la même icône couvre une étendue de valeurs différente selon la plage. Dans une plage de 10 à 90, l'icône verte couvre environ 60 à 90 ; dans une plage de 10 à 900, elle couvre environ 600 à 900. Les bandes sont relatives, non absolues — ce qui est la valeur par défaut appropriée pour un tableau où chaque colonne a sa propre échelle, mais qu'il vaut mieux connaître si vous attendez un seuil fixe.
Choisir entre les trois
Les trois s'appliquent à une plage, les trois résident à l'intérieur des cellules et les trois relèvent de la mise en forme conditionnelle. Le choix dépend de ce que le lecteur doit faire des chiffres :
| Le lecteur doit | Utiliser | Parce que |
|---|---|---|
| Comparer des magnitudes sur une ligne ou une colonne | Barres de données | La longueur de la barre est le repère visuel le plus précis pour "combien" |
| Repérer les points chauds et froids dans un grand tableau | Échelles de couleurs | L'intensité de la couleur est perçue périphériquement même lorsque l'œil n'est pas focalisé sur une cellule précise |
| Classer les valeurs en quelques catégories de statut | Jeux d'icônes | Des icônes discrètes correspondent à des décisions discrètes — "ceci nécessite une attention", "ceci est correct" |
| Voir tout ce qui précède en même temps | Combiner sur différentes plages | Chaque mise en forme conditionnelle est indépendante ; appliquez des barres de données à une plage et des jeux d'icônes à une autre |
Les trois ne sont pas mutuellement exclusifs. Une feuille de calcul peut porter des barres de données sur les colonnes de chiffre d'affaires et des jeux d'icônes sur la colonne de taux de croissance dans le même enregistrement, car chaque appel à ConditionalFormats.Add crée un format indépendant lié à sa propre plage.
Personnaliser l'apparence des barres de données
La couleur de remplissage d'une barre de données provient de DataBar.BarColor. Définir uniquement FormatType sans BarColor produit le bleu par défaut. Une bordure est également disponible, mais elle a une dépendance : le type de bordure doit être défini avant que la couleur de bordure ne prenne effet.
// Set the border type first so that the border color takes effect
format.DataBar.BarBorder.Type = xlsModule.DataBarBorderType.DataBarBorderSolid;
format.DataBar.BarBorder.Color = xlsModule.Color.get_Red();
// Fill color of the bar
format.DataBar.BarColor = xlsModule.Color.get_GreenYellow();
Définir BarBorder.Color seul, sans définir d'abord BarBorder.Type, n'a aucun effet — la bordure n'est pas dessinée car aucun type de bordure n'a été déclaré. Les échelles de couleurs et les jeux d'icônes n'ont pas de propriétés d'apparence équivalentes ; leur style est déterminé par le type de format et, pour les jeux d'icônes, par l'énumération IconSetType.
Problèmes courants
Les cellules de texte dans la plage cible n'affichent aucune barre de données. C'est normal. Une barre de données exprime une magnitude relative, et seules les cellules numériques ont une magnitude. Les cellules de texte sont ignorées silencieusement — aucune erreur, aucune barre. Limitez la plage à la zone numérique.
Les barres de données sont toutes du bleu par défaut.
DataBar.BarColor n'a pas été défini après l'attribution de FormatType. Définissez-le sur n'importe quelle valeur xlsModule.Color pour modifier le remplissage.
La couleur de bordure de la barre de données ne s'affiche pas.
Le type de bordure n'a pas été défini en premier. Attribuez DataBar.BarBorder.Type avant DataBar.BarBorder.Color — la couleur ne prend effet qu'une fois un type de bordure pleine déclaré.
Aucun changement visible après l'application d'une mise en forme conditionnelle.
Vérifiez que la plage transmise à AddRange correspond à l'emplacement réel des données. Une plage pointant vers des cellules vides ne produit ni erreur ni résultat visible.
FAQ
Puis-je appliquer plusieurs mises en forme conditionnelles à la même plage ?
Oui. Chaque appel à ConditionalFormats.Add crée un format indépendant. Deux formats peuvent cibler la même plage, bien que le résultat visuel de la superposition d'une barre de données et d'une échelle de couleurs sur les mêmes cellules puisse être déroutant — il est généralement plus clair d'appliquer différents types à différentes plages.
Quelles versions d'Excel prennent en charge ces types de mise en forme conditionnelle ?
Les barres de données, les échelles de couleurs et les jeux d'icônes ont été introduits dans Excel 2007. L'exemple enregistre avec ExcelVersion.Version2010 pour garantir la compatibilité avec Excel 2010 et les versions ultérieures.
Ai-je besoin d'Excel installé pour appliquer une mise en forme conditionnelle ?
Non. Le moteur de feuille de calcul est fourni avec le paquet et s'exécute en WebAssembly dans le navigateur. La mise en forme conditionnelle est écrite en XML standard à l'intérieur du fichier .xlsx, et Excel la restitue à l'ouverture du fichier.
Puis-je définir des seuils personnalisés pour les jeux d'icônes ?
L'énumération IconSetType sélectionne un style d'icône prédéfini avec des limites de bandes prédéfinies. L'exemple utilise ThreeTrafficLights1, qui divise la plage en trois bandes égales.
La mise en forme conditionnelle survit-elle si le fichier est ouvert puis réenregistré dans Excel ?
Oui. La mise en forme conditionnelle fait partie des règles de format stockées dans la feuille de calcul, et non d'un artefact de rendu. Excel lit, préserve et réapplique les mêmes règles lors du recalcul.