تنسيق مخططات العروض التقديمية في C++
نظرة عامة
توضح هذه المقالة كيفية تنسيق المخططات في عروض PowerPoint باستخدام Aspose.Slides. تظهر كيفية تخصيص عناصر المخطط الأساسية مثل المحاور، وخطوط الشبكة، والعناوين، والوسائط، ومنطقة الرسم، وتعبئات الجدران لتحسين مظهر وقراءة بيانات المخطط.
كما توضح كيفية ضبط خصائص الخط لنص المخطط، وتطبيق تنسيقات عددية مسبقة على بيانات المخطط، وتمكين الزوايا المستديرة لمنطقة المخطط. معاً، تُظهر هذه الأمثلة كيفية التحكم في كل من النمط البصري وعرض البيانات للمخططات في العرض التقديمي.
تنسيق كيانات المخطط
استخدم IChart لتنسيق عناوين المخطط، والمحاور، وخطوط الشبكة، والوسائط، ومنطقة الرسم. يخلق هذا المثال مخططًا خطيًا مع علامات وبيانات افتراضية، ثم يطبق أنماط نصية وخطية منفصلة على محوري القيمة والفئة. يتم تحديد حجم الخطوط وعرض الخطوط بالنقاط؛ تُدوَّر تسميات الفئة بزاوية 45 درجة.
يستخدم محور القيمة get_NumberFormat بشكل مستقل عن خلايا المصدر. يتراوح مقياسه من -2 إلى 15، مع فواصل رئيسية قدرها 2 وفواصل فرعية قدرها 0.5. يجمع المثال أيضاً تنسيق النسبة المئوية مع get_DisplayUnit المضبط على الآلاف، لذا قم بتكييف هذه الإعدادات مع معنى وحجم بياناتك. تبقى الوسائط خارج منطقة الرسم لأن get_Overlay غير مفعلة. يتم تكوين تعبئات الجدار الخلفي والأرضية عبر get_BackWall وget_Floor، لكن هذه السطوح لا تظهر إلا في المخططات ثلاثية الأبعاد.
#include <system/shared_ptr.h>
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <Export/SaveFormat.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartTextFormat.h>
#include <DOM/Chart/IChartPortionFormat.h>
#include <DOM/IPortionFormat.h>
#include <drawing/color.h>
#include <DOM/FillType.h>
#include <DOM/NullableBool.h>
#include <DOM/LineDashStyle.h>
#include <DOM/Fonts/FontData.h>
#include <DOM/IFillFormat.h>
#include <DOM/IColorFormat.h>
#include <DOM/ILineFormat.h>
#include <DOM/ILineFillFormat.h>
#include <DOM/ITextFrame.h>
#include <DOM/IParagraphCollection.h>
#include <DOM/IParagraph.h>
#include <DOM/IPortionCollection.h>
#include <DOM/IPortion.h>
#include <DOM/Chart/IAxesManager.h>
#include <DOM/Chart/IAxis.h>
#include <DOM/Chart/IChartLinesFormat.h>
#include <DOM/Chart/IChartTitle.h>
#include <DOM/Chart/IFormat.h>
#include <DOM/Chart/DisplayUnitType.h>
#include <DOM/Chart/TickLabelPositionType.h>
#include <DOM/Chart/ILegend.h>
#include <DOM/Chart/IChartWall.h>
#include <DOM/Chart/IChartPlotArea.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::LineWithMarkers, 50, 50, 500, 400);
chart->set_HasTitle(true);
chart->get_ChartTitle()->AddTextFrameForOverriding(u"");
auto chartTitle = chart->get_ChartTitle()->get_TextFrameForOverriding()->get_Paragraphs()->idx_get(0)->get_Portions()->idx_get(0);
chartTitle->set_Text(u"Sample Chart");
chartTitle->get_PortionFormat()->get_FillFormat()->set_FillType(FillType::Solid);
chartTitle->get_PortionFormat()->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Gray());
chartTitle->get_PortionFormat()->set_FontHeight(20);
chartTitle->get_PortionFormat()->set_FontBold(NullableBool::True);
chartTitle->get_PortionFormat()->set_FontItalic(NullableBool::True);
chart->get_Axes()->get_VerticalAxis()->get_MajorGridLinesFormat()->get_Line()->get_FillFormat()->set_FillType(FillType::Solid);
chart->get_Axes()->get_VerticalAxis()->get_MajorGridLinesFormat()->get_Line()->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Blue());
chart->get_Axes()->get_VerticalAxis()->get_MajorGridLinesFormat()->get_Line()->set_Width(5);
chart->get_Axes()->get_VerticalAxis()->get_MajorGridLinesFormat()->get_Line()->set_DashStyle(LineDashStyle::DashDot);
chart->get_Axes()->get_VerticalAxis()->get_MinorGridLinesFormat()->get_Line()->get_FillFormat()->set_FillType(FillType::Solid);
chart->get_Axes()->get_VerticalAxis()->get_MinorGridLinesFormat()->get_Line()->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Red());
chart->get_Axes()->get_VerticalAxis()->get_MinorGridLinesFormat()->get_Line()->set_Width(3);
chart->get_Axes()->get_VerticalAxis()->set_IsNumberFormatLinkedToSource(false);
chart->get_Axes()->get_VerticalAxis()->set_DisplayUnit(DisplayUnitType::Thousands);
chart->get_Axes()->get_VerticalAxis()->set_NumberFormat(u"0.0%");
chart->get_Axes()->get_VerticalAxis()->set_IsAutomaticMajorUnit(false);
chart->get_Axes()->get_VerticalAxis()->set_IsAutomaticMaxValue(false);
chart->get_Axes()->get_VerticalAxis()->set_IsAutomaticMinorUnit(false);
chart->get_Axes()->get_VerticalAxis()->set_IsAutomaticMinValue(false);
chart->get_Axes()->get_VerticalAxis()->set_MaxValue(15.0f);
chart->get_Axes()->get_VerticalAxis()->set_MinValue(-2.0f);
chart->get_Axes()->get_VerticalAxis()->set_MinorUnit(0.5f);
chart->get_Axes()->get_VerticalAxis()->set_MajorUnit(2.0f);
auto valueAxisText = chart->get_Axes()->get_VerticalAxis()->get_TextFormat()->get_PortionFormat();
valueAxisText->set_FontBold(NullableBool::True);
valueAxisText->set_FontHeight(16);
valueAxisText->set_FontItalic(NullableBool::True);
valueAxisText->get_FillFormat()->set_FillType(FillType::Solid);
valueAxisText->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_DarkGreen());
auto valueAxisFont = System::MakeObject<FontData>(u"Times New Roman");
valueAxisText->set_LatinFont(valueAxisFont);
chart->get_Axes()->get_VerticalAxis()->set_HasTitle(true);
chart->get_Axes()->get_VerticalAxis()->get_Title()->AddTextFrameForOverriding(u"");
auto valueAxisTitle = chart->get_Axes()->get_VerticalAxis()->get_Title()->get_TextFrameForOverriding()->get_Paragraphs()->idx_get(0)->get_Portions()->idx_get(0);
valueAxisTitle->set_Text(u"Primary Axis");
valueAxisTitle->get_PortionFormat()->get_FillFormat()->set_FillType(FillType::Solid);
valueAxisTitle->get_PortionFormat()->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Gray());
valueAxisTitle->get_PortionFormat()->set_FontHeight(20);
valueAxisTitle->get_PortionFormat()->set_FontBold(NullableBool::True);
valueAxisTitle->get_PortionFormat()->set_FontItalic(NullableBool::True);
chart->get_Axes()->get_HorizontalAxis()->get_MajorGridLinesFormat()->get_Line()->get_FillFormat()->set_FillType(FillType::Solid);
chart->get_Axes()->get_HorizontalAxis()->get_MajorGridLinesFormat()->get_Line()->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Green());
chart->get_Axes()->get_HorizontalAxis()->get_MajorGridLinesFormat()->get_Line()->set_Width(5);
chart->get_Axes()->get_HorizontalAxis()->get_MinorGridLinesFormat()->get_Line()->get_FillFormat()->set_FillType(FillType::Solid);
chart->get_Axes()->get_HorizontalAxis()->get_MinorGridLinesFormat()->get_Line()->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Yellow());
chart->get_Axes()->get_HorizontalAxis()->get_MinorGridLinesFormat()->get_Line()->set_Width(3);
auto categoryAxisText = chart->get_Axes()->get_HorizontalAxis()->get_TextFormat()->get_PortionFormat();
categoryAxisText->set_FontBold(NullableBool::True);
categoryAxisText->set_FontHeight(16);
categoryAxisText->set_FontItalic(NullableBool::True);
categoryAxisText->get_FillFormat()->set_FillType(FillType::Solid);
categoryAxisText->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Blue());
auto categoryAxisFont = System::MakeObject<FontData>(u"Arial");
categoryAxisText->set_LatinFont(categoryAxisFont);
chart->get_Axes()->get_HorizontalAxis()->set_HasTitle(true);
chart->get_Axes()->get_HorizontalAxis()->get_Title()->AddTextFrameForOverriding(u"");
auto categoryAxisTitle = chart->get_Axes()->get_HorizontalAxis()->get_Title()->get_TextFrameForOverriding()->get_Paragraphs()->idx_get(0)->get_Portions()->idx_get(0);
categoryAxisTitle->set_Text(u"Sample Category");
categoryAxisTitle->get_PortionFormat()->get_FillFormat()->set_FillType(FillType::Solid);
categoryAxisTitle->get_PortionFormat()->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Gray());
categoryAxisTitle->set_FontHeight(20);
categoryAxisTitle->set_FontBold(NullableBool::True);
categoryAxisTitle->set_FontItalic(NullableBool::True);
chart->get_Axes()->get_HorizontalAxis()->set_TickLabelPosition(TickLabelPositionType::Low);
chart->get_Axes()->get_HorizontalAxis()->set_TickLabelRotationAngle(45);
auto legendText = chart->get_Legend()->get_TextFormat()->get_PortionFormat();
legendText->set_FontBold(NullableBool::True);
legendText->set_FontHeight(16);
legendText->set_FontItalic(NullableBool::True);
legendText->get_FillFormat()->set_FillType(FillType::Solid);
legendText->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_DarkRed());
chart->get_Legend()->set_Overlay(false);
chart->get_BackWall()->set_Thickness(1);
chart->get_BackWall()->get_Format()->get_Fill()->set_FillType(FillType::Solid);
chart->get_BackWall()->get_Format()->get_Fill()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Orange());
chart->get_Floor()->get_Format()->get_Fill()->set_FillType(FillType::Solid);
chart->get_Floor()->get_Format()->get_Fill()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Red());
chart->get_PlotArea()->get_Format()->get_Fill()->set_FillType(FillType::Solid);
chart->get_PlotArea()->get_Format()->get_Fill()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_LightCyan());
presentation->Save(u"FormattedChart_out.pptx", SaveFormat::Pptx);
ضبط خصائص الخط للمخطط
قم بتعيين حجم الخط الافتراضي لنص المخطط عبر Chart::get_TextFormat. ينشئ المثال مخطط أعمدة مع تكتلات بخط 20 نقطة ويمكّن تسميات القيم للسلسلة الأولى عبر set_ShowValue. يمكن لعناصر النص التي لها إعدادات خط صريحة خاصة أن تتجاوز الإعداد الافتراضي للمخطط.
#include <system/shared_ptr.h>
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <Export/SaveFormat.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartTextFormat.h>
#include <DOM/Chart/IChartPortionFormat.h>
#include <DOM/IPortionFormat.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IDataLabelCollection.h>
#include <DOM/Chart/IDataLabelFormat.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::ClusteredColumn, 100, 100, 500, 400);
chart->get_TextFormat()->get_PortionFormat()->set_FontHeight(20);
chart->get_ChartData()->get_Series()->idx_get(0)->get_Labels()->get_DefaultDataLabelFormat()->set_ShowValue(true);
presentation->Save(u"FontPropertiesForChart.pptx", SaveFormat::Pptx);
ضبط التنسيق الرقمي
استخدم IChartDataCell::set_PresetNumberFormat لتطبيق تنسيق رقمي مدمج على خلايا دفتر عمل المخطط. يُنشئ هذا المثال مخطط أعمدة مع تكتلات ببيانات افتراضية مدعومة بالخلايا ويطبق فهرس التنسيق 10 (0.00%) على خلية قيمة كل سلسلة. يغيّر هذا طريقة عرض القيم في دفتر العمل دون تعديل الأعداد الأساسية؛ على سبيل المثال، يُعرض 0.25 كـ 25.00%. يمكن تكوين تنسيقات المحاور وتسمية البيانات بشكل منفصل.
#include <system/shared_ptr.h>
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <Export/SaveFormat.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartTextFormat.h>
#include <DOM/Chart/IChartPortionFormat.h>
#include <DOM/IPortionFormat.h>
#include <DOM/Chart/IChartData.h>
#include <DOM/Chart/IChartSeriesCollection.h>
#include <DOM/Chart/IChartSeries.h>
#include <DOM/Chart/IChartDataPointCollection.h>
#include <DOM/Chart/IChartDataPoint.h>
#include <DOM/Chart/IDoubleChartValue.h>
#include <DOM/Chart/IChartDataCell.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::ClusteredColumn, 50, 50, 500, 400);
auto series = chart->get_ChartData()->get_Series();
for (auto chartSeries : series)
{
for (auto dataPoint : chartSeries->get_DataPoints())
{
dataPoint->get_Value()->get_AsCell()->set_PresetNumberFormat(10); // 0.00%
}
}
presentation->Save(u"PresetNumberFormat_out.pptx", SaveFormat::Pptx);
القائمة التالية تُظهر جداول فهارس تنسيقات الأرقام المدمجة مع صيغ Excel تمثيلية للمنطقة الإنجليزية (الولايات المتحدة). قد تختلف سلاسل التنسيق الدقيقة وعرضها بحسب التطبيق والمنطقة، خصوصاً للعملات والتواريخ. بعض صيغ Excel تختلف أيضاً عن القيم الافتراضية في معيار OOXML، كما هو موضح في Microsoft’s number format implementation notes.
| الفهرس | التنسيق |
|---|---|
| 0 | General |
| 1 | 0 |
| 2 | 0.00 |
| 3 | #,##0 |
| 4 | #,##0.00 |
| 5 | "$"#,##0_);("$"#,##0) |
| 6 | "$"#,##0_);[Red]("$"#,##0) |
| 7 | "$"#,##0.00_);("$"#,##0.00) |
| 8 | "$"#,##0.00_);[Red]("$"#,##0.00) |
| 9 | 0% |
| 10 | 0.00% |
| 11 | 0.00E+00 |
| 12 | # ?/? |
| 13 | # ??/?? |
| 14 | m/d/yyyy |
| 15 | d-mmm-yy |
| 16 | d-mmm |
| 17 | mmm-yy |
| 18 | h:mm AM/PM |
| 19 | h:mm:ss AM/PM |
| 20 | h:mm |
| 21 | h:mm:ss |
| 22 | m/d/yyyy h:mm |
| 37 | #,##0_);(#,##0) |
| 38 | #,##0_);[Red](#,##0) |
| 39 | #,##0.00_);(#,##0.00) |
| 40 | #,##0.00_);[Red](#,##0.00) |
| 41 | _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_) |
| 42 | _("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_) |
| 43 | _(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_) |
| 44 | _("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_) |
| 45 | mm:ss |
| 46 | [h]:mm:ss |
| 47 | mm:ss.0 |
| 48 | ##0.0E+0 |
| 49 | @ |
تعيين حدود مستديرة لمنطقة المخطط
فعّل IChart::set_HasRoundedCorners لتقوّي الزوايا لمنطقة المخطط. ينشئ المثال مخطط أعمدة مع تكتلات ويستخدم get_LineFormat لمنح حدوده لونًا رماديًا صلبًا ونمط خط واحد قبل حفظ العرض التقديمي.
#include <system/shared_ptr.h>
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <Export/SaveFormat.h>
#include <DOM/Chart/ChartType.h>
#include <DOM/Chart/IChartTextFormat.h>
#include <DOM/Chart/IChartPortionFormat.h>
#include <DOM/IPortionFormat.h>
#include <drawing/color.h>
#include <DOM/FillType.h>
#include <DOM/LineStyle.h>
#include <DOM/ILineFormat.h>
#include <DOM/ILineFillFormat.h>
#include <DOM/IColorFormat.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
auto presentation = System::MakeObject<Presentation>();
auto slide = presentation->get_Slide(0);
auto chart = slide->get_Shapes()->AddChart(ChartType::ClusteredColumn, 20, 100, 600, 400);
chart->get_LineFormat()->get_FillFormat()->set_FillType(FillType::Solid);
chart->get_LineFormat()->get_FillFormat()->get_SolidFillColor()->set_Color(System::Drawing::Color::get_Gray());
chart->get_LineFormat()->set_Style(LineStyle::Single);
chart->set_HasRoundedCorners(true);
presentation->Save(u"out.pptx", SaveFormat::Pptx);
تحرير تعليقات المخطط الموجودة
يمكن للمخطط أن يحتوي على أشكال مخصصة، مثل تعليق نصي يوضح حالة تقرير. يمكن الوصول إلى هذه الأشكال عبر IChart::get_UserShapes، كما هو مُدرج تحت Chart::get_UserShapes في مرجع API للمخطط. تحتوي مجموعة get_Shapes الخاصة به على الأشكال المملوكة للمخطط.
مربع نص عادي يتم وضعه فوق مخطط ينتمي إلى الشريحة، حتى لو بدا كجزء من المخطط. يعثر التكرار عبر Slide::get_Shapes على المخطط والأشكال العادية في الشريحة، لكنه لا يسرد الأشكال الفردية داخل المخطط. عناوين المخطط وتسمية البيانات هي عناصر مخطط منفصلة، وليست تعليقات مخصصة في هذه المجموعة.
قم بتنزيل chart-annotations.pptx وضعه في دليل العمل للتطبيق. تحتوي شريحته الأولى على مخطط مع تعليق غير مجمع يقرأ “النتائج الأولية”، وخط مملوك للمخطط، ومربع نص عادي على الشريحة يقرأ “تراكب الشريحة”. يجد المثال أول مخطط في تلك الشريحة ويغيّر التعليق إلى “النتائج النهائية” عندما يكون التقرير جاهزاً للنشر. يتحقق من مجموعة فارغة ولا يحرر سوى IAutoShape الذي يحتوي على get_TextFrame غير فارغ والنص المتوقع.
#include <system/shared_ptr.h>
#include <DOM/Presentation.h>
#include <DOM/ISlide.h>
#include <DOM/IShapeCollection.h>
#include <DOM/IChart.h>
#include <Export/SaveFormat.h>
#include <system/console.h>
#include <DOM/IGroupShape.h>
#include <DOM/IAutoShape.h>
#include <DOM/ITextFrame.h>
using namespace Aspose::Slides;
using namespace Aspose::Slides::Charts;
using namespace Aspose::Slides::Export;
auto presentation = System::MakeObject<Presentation>(u"chart-annotations.pptx");
auto slide = presentation->get_Slide(0);
System::SharedPtr<IChart> chart;
for (auto shape : slide->get_Shapes())
{
auto candidate = System::DynamicCast<IChart>(shape);
if (candidate != nullptr)
{
chart = candidate;
break;
}
}
if (chart == nullptr || chart->get_UserShapes()->get_Shapes()->get_Count() == 0)
{
System::Console::WriteLine(u"No chart or chart-owned shapes found.");
return;
}
auto updated = false;
for (auto shape : chart->get_UserShapes()->get_Shapes())
{
auto annotation = System::DynamicCast<IAutoShape>(shape);
if (annotation != nullptr &&
annotation->get_TextFrame() != nullptr &&
annotation->get_TextFrame()->get_Text() == u"Preliminary results")
{
annotation->get_TextFrame()->set_Text(u"Final results");
updated = true;
break;
}
}
if (updated)
{
presentation->Save(u"chart-annotations-updated.pptx", SaveFormat::Pptx);
}
else
{
System::Console::WriteLine(u"No matching text annotation found.");
}
يبقى الخط ومربع النص على الشريحة دون تغيير. تظهر الصور التالية الإدخال والنتيجة المحفوظة والمفتوحة مرة أخرى:
| قبل التحرير | بعد التحرير |
|---|---|
![]() |
![]() |
Note
يفحص المثال فقط الأشكال المملوكة للمخطط على المستوى الأعلى. إذا كان التعليق داخل IGroupShape، فافحص مجموعة get_Shapes الخاصة بذلك التجميع أيضًا. كرّر ذلك بصورة متكررة للمجموعات المتداخلة، مع تطبيق نفس فحوصات النص على الأشكال الفرعية. التجميع ذاته هو حاوية؛ لا تعاملها كمربع نص.الأسئلة المتكررة
هل يمكنني تعيين تعبئات شبه شفافة للأعمدة/المناطق مع الحفاظ على الحدود غير شفافة؟ نعم. يتم تكوين شفافية التعبئة والحدود بشكل منفصل. هذا مفيد لتحسين قابلية قراءة الشبكة والبيانات في التصورات المكتظة.
كيف يمكنني التعامل مع تسميات البيانات عندما تتداخل؟ قلل حجم الخط، عطل مكونات التسمية غير الضرورية (مثل الفئات)، اضبط موضع التسمية، اعرض التسميات فقط للنقاط المحددة إذا لزم الأمر، أو غيّر التنسيق إلى “القيمة + الوسيط”.
هل يمكنني تطبيق تعبئات متدرجة أو نمطية على السلاسل؟ نعم. تدعم السلاسل تعبئات صلبة ومتدرجة ونمطية. في التطبيق، استخدم المتدرجات بشكل معتدل وتجنب التركيبات التي تقلل من التباين مع الشبكة والنص.

