使用 JavaScript 在簡報中管理圖表資料標籤
簡介
Data labels display information about chart series and individual data points, helping readers identify values and understand the chart. This article explains how to format values, display percentages, read label text, control labels beyond the axis maximum, adjust category axis label spacing, and position pie chart labels.
設定圖表資料標籤的資料精度
使用 setNumberFormatOfValues 來格式化系列值。此範例建立一個具有預設資料的折線圖,顯示其資料表,並為第一個系列啟用值標籤。格式 #,##0.00 會顯示千位分隔符號和兩位小數,而不會更改底層的值。
const aspose = { slides: require("aspose.slides.via.java") };
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.Line, 50, 50, 450, 300);
chart.setDataTable(true);
const series = chart.getChartData().getSeries().get_Item(0);
series.setNumberFormatOfValues("#,##0.00");
series.getLabels().getDefaultDataLabelFormat().setShowValue(true);
presentation.save("PrecisionOfDatalabels_out.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
若要格式化圖表內嵌工作簿中的數值儲存格,請參閱 設定工作簿儲存格的自訂數字格式。該範例亦顯示值標籤遵循其來源儲存格格式,同時保留儲存的數值。
以百分比作為標籤
對於堆疊直條圖,將每個值計算為其類別總和的百分比,並將文字指定給由 getTextFrameForOverriding 回傳的文字框。本範例使用預設圖表資料,並以 8 點字型顯示帶兩位小數的百分比。總和為零的類別會被跳過,以避免除以零。若圖表資料變更,請重新計算自訂標籤文字。
const aspose = { slides: require("aspose.slides.via.java") };
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.StackedColumn, 20, 20, 400, 400);
const categoryTotals = new Array(chart.getChartData().getCategories().size()).fill(0);
for (let k = 0; k < chart.getChartData().getCategories().size(); k++) {
for (let i = 0; i < chart.getChartData().getSeries().size(); i++) {
const series = chart.getChartData().getSeries().get_Item(i);
const pointValue = series.getDataPoints().get_Item(k).getValue().getData();
categoryTotals[k] += Number(pointValue);
}
}
for (let x = 0; x < chart.getChartData().getSeries().size(); x++) {
const series = chart.getChartData().getSeries().get_Item(x);
series.getLabels().getDefaultDataLabelFormat().setShowLegendKey(false);
for (let j = 0; j < series.getDataPoints().size(); j++) {
const label = series.getDataPoints().get_Item(j).getLabel();
if (categoryTotals[j] == 0) {
continue;
}
const pointValue = series.getDataPoints().get_Item(j).getValue().getData();
const dataPointPercent = (Number(pointValue) / categoryTotals[j]) * 100;
const portion = new aspose.slides.Portion();
portion.setText(dataPointPercent.toFixed(2) + " %");
portion.getPortionFormat().setFontHeight(8);
label.getTextFrameForOverriding().setText("");
const paragraph = label.getTextFrameForOverriding().getParagraphs().get_Item(0);
paragraph.getPortions().add(portion);
label.getDataLabelFormat().setShowValue(true);
label.getDataLabelFormat().setShowSeriesName(false);
label.getDataLabelFormat().setShowPercentage(false);
label.getDataLabelFormat().setShowLegendKey(false);
label.getDataLabelFormat().setShowCategoryName(false);
label.getDataLabelFormat().setShowBubbleSize(false);
}
}
presentation.save("DisplayPercentageAsLabels_out.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
使用圖表資料標籤設定百分比符號
當值以分數形式儲存時,使用 setNumberFormat 顯示百分比。將 false 傳遞給 setNumberFormatLinkedToSource 以使標籤格式獨立於來源儲存格。
此範例建立一個 100% 堆疊直條圖,四個類別各有紅色和藍色系列。每對值相加皆為 1。標籤格式 0.0% 會將 0.30 顯示為 30.0%,而垂直軸使用兩位小數。兩個系列的標籤文字皆為白色、10 點字型。
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.PercentsStackedColumn, 20, 20, 500, 400);
chart.getAxes().getVerticalAxis().setNumberFormatLinkedToSource(false);
chart.getAxes().getVerticalAxis().setNumberFormat("0.00%");
chart.getChartData().getSeries().clear();
chart.getChartData().getCategories().clear();
const workbook = chart.getChartData().getChartDataWorkbook();
const worksheetIndex = 0;
for (let i = 0; i < 4; i++) {
const categoryCell = workbook.getCell(worksheetIndex, i + 1, 0, "Category " + (i + 1));
chart.getChartData().getCategories().add(categoryCell);
}
const seriesNames = ["Reds", "Blues"];
const white = java.getStaticFieldValue("java.awt.Color", "WHITE");
const seriesColors = [java.getStaticFieldValue("java.awt.Color", "RED"), java.getStaticFieldValue("java.awt.Color", "BLUE")];
const values = [[0.30, 0.50, 0.80, 0.65], [0.70, 0.50, 0.20, 0.35]];
for (let i = 0; i < seriesNames.length; i++) {
const seriesCell = workbook.getCell(worksheetIndex, 0, i + 1, seriesNames[i]);
const series = chart.getChartData().getSeries().add(seriesCell, chart.getType());
for (let j = 0; j < 4; j++) {
const valueCell = workbook.getCell(worksheetIndex, j + 1, i + 1, values[i][j]);
series.getDataPoints().addDataPointForBarSeries(valueCell);
}
series.getFormat().getFill().setFillType(java.newByte(aspose.slides.FillType.Solid));
series.getFormat().getFill().getSolidFillColor().setColor(seriesColors[i]);
const labelFormat = series.getLabels().getDefaultDataLabelFormat();
labelFormat.setShowValue(true);
labelFormat.setNumberFormatLinkedToSource(false);
labelFormat.setNumberFormat("0.0%");
labelFormat.getTextFormat().getPortionFormat().setFontHeight(10);
labelFormat.getTextFormat().getPortionFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
labelFormat.getTextFormat().getPortionFormat().getFillFormat().getSolidFillColor().setColor(white);
}
presentation.save("SetDataLabelsPercentageSign_out.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
讀取資料標籤的實際文字
使用 getActualLabelText 取得資料標籤設定所產生的文字。這在擷取報表標籤、搜尋簡報內容或驗證產生的圖表時很有用。在下方範例中,預設的 data label format 將每個類別名稱、系列名稱與數值結合。某一點將其數值格式化為百分比,另一點則使用來自 getTextFrameForOverriding 的自訂文字。
const aspose = { slides: require("aspose.slides.via.java") };
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.ClusteredColumn, 20, 20, 500, 300);
chart.getChartData().getSeries().clear();
chart.getChartData().getCategories().clear();
const workbook = chart.getChartData().getChartDataWorkbook();
const firstCategoryCell = workbook.getCell(0, 1, 0, "Q1");
chart.getChartData().getCategories().add(firstCategoryCell);
const secondCategoryCell = workbook.getCell(0, 2, 0, "Q2");
chart.getChartData().getCategories().add(secondCategoryCell);
const northSeriesCell = workbook.getCell(0, 0, 1, "North");
const north = chart.getChartData().getSeries().add(northSeriesCell, chart.getType());
const northFirstValueCell = workbook.getCell(0, 1, 1, 0.25);
north.getDataPoints().addDataPointForBarSeries(northFirstValueCell);
const northSecondValueCell = workbook.getCell(0, 2, 1, 0.75);
north.getDataPoints().addDataPointForBarSeries(northSecondValueCell);
const southSeriesCell = workbook.getCell(0, 0, 2, "South");
const south = chart.getChartData().getSeries().add(southSeriesCell, chart.getType());
const southFirstValueCell = workbook.getCell(0, 1, 2, 0.40);
south.getDataPoints().addDataPointForBarSeries(southFirstValueCell);
const southSecondValueCell = workbook.getCell(0, 2, 2, 0.60);
south.getDataPoints().addDataPointForBarSeries(southSecondValueCell);
for (let i = 0; i < chart.getChartData().getSeries().size(); i++) {
const series = chart.getChartData().getSeries().get_Item(i);
const format = series.getLabels().getDefaultDataLabelFormat();
format.setShowCategoryName(true);
format.setShowSeriesName(true);
format.setShowValue(true);
}
north.getLabels().get_Item(1).getDataLabelFormat().setNumberFormatLinkedToSource(false);
north.getLabels().get_Item(1).getDataLabelFormat().setNumberFormat("0%");
south.getLabels().get_Item(0).getTextFrameForOverriding().setText("Reviewed");
for (let i = 0; i < chart.getChartData().getSeries().size(); i++) {
const series = chart.getChartData().getSeries().get_Item(i);
for (let j = 0; j < series.getDataPoints().size(); j++) {
const point = series.getDataPoints().get_Item(j);
const label = point.getLabel();
if (!label.isVisible()) {
continue;
}
console.log("Value: " + point.getValue().getData() + "; label: " + label.getActualLabelText());
}
}
} finally {
presentation.dispose();
}
儲存在資料點中的數字仍為 0.75,即使其標籤顯示 75% 並附帶類別和系列名稱。自訂文字會取代產生的標籤文字。無論哪種情況,getActualLabelText 都會回傳最終的標籤字串。若只想擷取可見標籤,請另行檢查 isVisible(如上所示)。
控制軸上限之外的資料標籤
手動限制軸範圍時,某些資料點可能超過其最大值。使用 setShowDataLabelsOverMaximum 來控制是否顯示其資料標籤。此設定會變更標籤可見性,但不會改變軸範圍或底層資料值。
以下範例建立一個 2D 群組直條圖,值為 60 與 120。它對 setAutomaticMaxValue 傳遞 false,並在垂直軸上使用 setMaxValue 設定最大值為 100。第一張投影片允許標籤超出最大值;其複本則停用此功能。兩張投影片皆儲存為 DataLabelsOverMaximum.pptx。
使用 setShowValue 啟用值標籤。圖表層級的設定本身不會啟用值顯示,也不會覆寫個別標籤已停用的值顯示。此範例為整個系列啟用值,並使用 setPosition 將標籤放置於每個柱形的外端。
const aspose = { slides: require("aspose.slides.via.java") };
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.ClusteredColumn, 50, 50, 600, 400);
chart.setLegend(false);
chart.getChartData().getSeries().clear();
chart.getChartData().getCategories().clear();
const workbook = chart.getChartData().getChartDataWorkbook();
const firstCategory = workbook.getCell(0, 1, 0, "Within range");
const secondCategory = workbook.getCell(0, 2, 0, "Above maximum");
chart.getChartData().getCategories().add(firstCategory);
chart.getChartData().getCategories().add(secondCategory);
const seriesName = workbook.getCell(0, 0, 1, "Values");
const series = chart.getChartData().getSeries().add(seriesName, chart.getType());
const firstValue = workbook.getCell(0, 1, 1, 60);
const secondValue = workbook.getCell(0, 2, 1, 120);
series.getDataPoints().addDataPointForBarSeries(firstValue);
series.getDataPoints().addDataPointForBarSeries(secondValue);
series.getLabels().getDefaultDataLabelFormat().setShowValue(true);
series.getLabels().getDefaultDataLabelFormat().setPosition(aspose.slides.LegendDataLabelPosition.OutsideEnd);
chart.getAxes().getVerticalAxis().setAutomaticMaxValue(false);
chart.getAxes().getVerticalAxis().setMaxValue(100);
chart.setShowDataLabelsOverMaximum(true);
const secondSlide = presentation.getSlides().addClone(slide);
const secondChart = secondSlide.getShapes().get_Item(0);
secondChart.setShowDataLabelsOverMaximum(false);
presentation.save("DataLabelsOverMaximum.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
以下影像顯示 Microsoft PowerPoint 渲染的已儲存投影片。設定為 true 時,標籤 120 會在上邊界可見;設定為 false 時則隱藏。標籤 60 保持可見,軸最大值仍為 100,且第二個資料點在兩種情況下均為 120。
| setShowDataLabelsOverMaximum(true) | setShowDataLabelsOverMaximum(false) |
|---|---|
![]() |
![]() |
圖表類型
此範例使用帶值軸的 2D 直條圖。沒有值軸的圖表(例如圓形圖與環形圖)沒有可限制的軸上限。設定標籤與軸之間的距離
使用 setLabelOffset 控制類別軸標籤與軸之間的距離。該值是軸標籤最大字型大小的百分比。此範例建立一個群組直條圖,並將水平軸標籤偏移設定為 500。此設定影響類別軸標籤,而非附加於個別資料點的標籤。
const aspose = { slides: require("aspose.slides.via.java") };
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.ClusteredColumn, 20, 20, 500, 300);
chart.getAxes().getHorizontalAxis().setLabelOffset(500);
presentation.save("SetCategoryAxisLabelDistance_out.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
調整標籤位置
在圓形圖上,調整資料標籤位置以改善間距並為引線留出空間。
此範例顯示第一個資料點的數值,將其標籤放置在切片外部,並使用 setX 與 setY 調整水平與垂直偏移。這些偏移分別相對於圖表的寬度與高度。
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.Pie, 50, 50, 200, 200);
const series = chart.getChartData().getSeries();
const label = series.get_Item(0).getLabels().get_Item(0);
label.getDataLabelFormat().setShowValue(true);
label.getDataLabelFormat().setPosition(aspose.slides.LegendDataLabelPosition.OutsideEnd);
label.setX(java.newFloat(0.71));
label.setY(java.newFloat(0.04));
presentation.save("presentation.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}

設定引線格式
當圓形圖的標籤位於切片外部時,引線可協助讀者將每個數值對應至正確的切片。使用對比色且略粗的線條可提升可讀性,而透明度與虛線樣式則可使線條不那麼突兀。
使用 getLeaderLinesFormat 在系列的資料標籤集合層級設定引線格式。series.getLabels().getLeaderLinesFormat().getLine() 的設定會套用於整個集合,而非單一標籤。
此範例建立一個預設資料的圓形圖,將數值顯示在切片外側,並啟用 setShowLeaderLines。它使用 setX 與 setY 將兩個標籤向外移動,偏移以圖表寬高的比例表示。此範例不需要輸入簡報。
線條的 getFillFormat 設定為不透明度 191(255 為滿)的實心藍色,約 25% 透明度。setWidth 設定粗細為 2 點,setDashStyle 則使線條呈虛線。
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.Pie, 80, 50, 560, 400);
chart.setLegend(false);
const series = chart.getChartData().getSeries().get_Item(0);
const labelFormat = series.getLabels().getDefaultDataLabelFormat();
labelFormat.setShowValue(true);
labelFormat.setPosition(aspose.slides.LegendDataLabelPosition.OutsideEnd);
labelFormat.setShowLeaderLines(true);
// 將兩個標籤從切片向外移動更遠。
series.getLabels().get_Item(0).setX(java.newFloat(0.10));
series.getLabels().get_Item(0).setY(java.newFloat(-0.05));
series.getLabels().get_Item(1).setX(java.newFloat(-0.10));
series.getLabels().get_Item(1).setY(java.newFloat(0.05));
const line = series.getLabels().getLeaderLinesFormat().getLine();
line.getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
const lineColor = java.newInstanceSync("java.awt.Color", 30, 90, 160, 191);
line.getFillFormat().getSolidFillColor().setColor(lineColor);
line.setWidth(2);
line.setDashStyle(java.newByte(aspose.slides.LineDashStyle.Dash));
presentation.save("FormattedLeaderLines.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
啟用引線並不保證每個標籤皆會出現線條。可見性取決於標籤的位置與圖表的版面配置行為。在此範例中,兩個被移動的標籤有可見的引線;靠近切片的標籤則不需要引線。
以下影像顯示以 Aspose.Slides 渲染的已儲存 FormattedLeaderLines.pptx:

在柱狀圖上方新增多列資料標籤
此範例建立一個柱狀圖,於繪圖區上方放置兩列資料標籤。Series A 顯示可見的柱形,Series B 與 Series C 則提供額外的標籤。透過移除填滿與外框將它們的柱形隱藏。使用 ChartSeriesGroup.setOverlap 方法使三個系列的類別中心對齊。
ChartPlotArea 設定保留標籤列的空間。於 Chart.validateChartLayout 計算預設位置後,DataLabel.setX 與 DataLabel.setY 保持水平對齊並套用垂直偏移,以將標籤排列成兩列。數字仍為連結至系列值的資料標籤;僅有列標題是獨立的文字圖形。
const aspose = { slides: require("aspose.slides.via.java") };
const java = require("java");
const black = java.getStaticFieldValue("java.awt.Color", "BLACK");
const presentation = new aspose.slides.Presentation();
try {
const slide = presentation.getSlides().get_Item(0);
const chart = slide.getShapes().addChart(aspose.slides.ChartType.ClusteredColumn, 40, 40, 640, 200);
chart.setTitle(false);
chart.setLegend(false);
chart.getTextFormat().getPortionFormat().setFontHeight(12);
chart.getChartData().getSeries().clear();
chart.getChartData().getCategories().clear();
const workbook = chart.getChartData().getChartDataWorkbook();
workbook.clear(0);
const categories = ["North", "South", "East", "West"];
const seriesNames = ["Series A", "Series B", "Series C"];
const seriesValues = [[35, 42, 28, 47], [22, 31, 19, 26], [12, 16, 14, 18]];
for (let categoryIndex = 0; categoryIndex < categories.length; categoryIndex++) {
const categoryCell = workbook.getCell(0, categoryIndex + 1, 0, categories[categoryIndex]);
chart.getChartData().getCategories().add(categoryCell);
}
for (let seriesIndex = 0; seriesIndex < seriesNames.length; seriesIndex++) {
const seriesCell = workbook.getCell(0, 0, seriesIndex + 1, seriesNames[seriesIndex]);
const series = chart.getChartData().getSeries().add(seriesCell, aspose.slides.ChartType.ClusteredColumn);
for (let categoryIndex = 0; categoryIndex < categories.length; categoryIndex++) {
const valueCell = workbook.getCell(0, categoryIndex + 1, seriesIndex + 1, seriesValues[seriesIndex][categoryIndex]);
series.getDataPoints().addDataPointForBarSeries(valueCell);
}
if (seriesIndex > 0) {
// 隱藏 B 與 C 系列的柱形,但保留它們的資料標籤。
series.getFormat().getFill().setFillType(java.newByte(aspose.slides.FillType.NoFill));
series.getFormat().getLine().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.NoFill));
series.getLabels().getDefaultDataLabelFormat().setShowValue(true);
series.getLabels().getDefaultDataLabelFormat().getTextFormat().getPortionFormat().setFontHeight(12);
const labelFill = series.getLabels().getDefaultDataLabelFormat().getTextFormat().getPortionFormat().getFillFormat();
labelFill.setFillType(java.newByte(aspose.slides.FillType.Solid));
labelFill.getSolidFillColor().setColor(black);
series.getLabels().getDefaultDataLabelFormat().setPosition(aspose.slides.LegendDataLabelPosition.InsideBase);
}
}
// 將所有三個系列對齊至相同的類別中心。
chart.getChartData().getSeries().get_Item(0).getParentSeriesGroup().setOverlap(java.newByte(100));
// 在此緊湊的範例中使用較少的格線。
chart.getAxes().getVerticalAxis().setAutomaticMajorUnit(false);
chart.getAxes().getVerticalAxis().setMajorUnit(10);
// 在繪圖區上方保留空間以放置兩列資料標籤。
chart.getPlotArea().setLayoutTargetType(aspose.slides.LayoutTargetType.Inner);
chart.getPlotArea().setX(java.newFloat(0.15));
chart.getPlotArea().setY(java.newFloat(0.32));
chart.getPlotArea().setWidth(java.newFloat(0.80));
chart.getPlotArea().setHeight(java.newFloat(0.48));
chart.validateChartLayout();
for (let seriesIndex = 1; seriesIndex < seriesNames.length; seriesIndex++) {
const series = chart.getChartData().getSeries().get_Item(seriesIndex);
const rowTop = seriesIndex == 1 ? 0.15 : 0.03;
for (let categoryIndex = 0; categoryIndex < categories.length; categoryIndex++) {
const dataLabel = series.getDataPoints().get_Item(categoryIndex).getLabel();
// 保留預設的水平位置。Y 為相對於
// 預設標籤位置的偏移,以圖表高度的比例表示。
dataLabel.setX(0);
dataLabel.setY(java.newFloat(rowTop - dataLabel.getActualY() / chart.getHeight()));
}
// 只有列標題是獨立的文字圖形。
const rowHeading = slide.getShapes().addAutoShape(aspose.slides.ShapeType.Rectangle, chart.getX(), chart.getY() + rowTop * chart.getHeight(), 85, 18);
rowHeading.getFillFormat().setFillType(java.newByte(aspose.slides.FillType.NoFill));
rowHeading.getLineFormat().getFillFormat().setFillType(java.newByte(aspose.slides.FillType.NoFill));
rowHeading.addTextFrame(seriesNames[seriesIndex]);
rowHeading.getTextFrame().getTextFrameFormat().setMarginTop(0);
rowHeading.getTextFrame().getTextFrameFormat().setMarginBottom(0);
const headingFormat = rowHeading.getTextFrame().getParagraphs().get_Item(0).getPortions().get_Item(0).getPortionFormat();
headingFormat.setFontHeight(12);
headingFormat.getFillFormat().setFillType(java.newByte(aspose.slides.FillType.Solid));
headingFormat.getFillFormat().getSolidFillColor().setColor(black);
}
presentation.save("multiple-rows-of-labels.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}

常見問題
如何防止在密集圖表上資料標籤重疊?
結合自動標籤放置、引線與縮小字型大小;必要時隱藏部分欄位(例如類別)或僅對極端值或關鍵點顯示標籤。
如何僅對零、負數或空值停用標籤?
在啟用標籤前先篩選資料點,並依照定義的規則關閉 0、負值或缺漏值的顯示。
如何在匯出為 PDF/影像時確保標籤樣式一致?
明確設定字型族與大小,並確認渲染環境中已安裝該字型,以避免回退。

