Every visual aspect of a FioriCharts chart is configurable through properties on ChartModel and a set of attributes classes. Because ChartModel is an ObservableObject, you can mutate these properties after the chart is displayed and the view updates automatically.
Series colors
ChartSeriesAttributes
ChartSeriesAttributes controls the line width, point appearance, and color palette for a single series. Pass an array to ChartModel.seriesAttributes — one element per series.
let series0 = ChartSeriesAttributes(
palette: ChartSeriesPalette(colors: [.blue]),
lineWidth: 2,
point: ChartPointAttributes(isHidden: false, diameter: 8, strokeColor: .blue)
)
let series1 = ChartSeriesAttributes(
palette: ChartSeriesPalette(colors: [.orange]),
lineWidth: 2,
point: ChartPointAttributes(isHidden: true)
)
let model = ChartModel(
chartType: .line,
data: [
[200, 170, 165, 143, 166, 112, 110],
[150, 120, 130, 135, 120, 138, 137]
],
titlesForCategory: [["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]],
seriesAttributes: [series0, series1]
)
ChartSeriesAttributes properties
| Property | Type | Default | Description |
|---|
palette | ChartSeriesPalette | System color | Color palette for the series |
lineWidth | CGFloat | 1 | Stroke width for lines (0–100) |
point | ChartPointAttributes | Default point | Point appearance |
firstLineCapDiameter | CGFloat | 0 | Diameter of the cap at the first data point |
lastLineCapDiameter | CGFloat | 0 | Diameter of the cap at the last data point |
ChartSeriesPalette
ChartSeriesPalette defines the colors used to render a series.
// Single solid color
let palette = ChartSeriesPalette(colors: [.systemBlue])
// Fill color distinct from the line color
let palette = ChartSeriesPalette(colors: [.blue], fillColor: .blue.opacity(0.2))
// With explicit label, positive, and negative colors
let palette = ChartSeriesPalette(
colors: [.blue],
fillColor: nil,
labelColor: .blue,
positiveMaxColor: .green,
positiveMinColor: .green.opacity(0.6),
negativeMaxColor: .red.opacity(0.6),
negativeMinColor: .red
)
| Property | Description |
|---|
colors | Primary color(s) for the series line. Stock charts can use multiple colors. |
fillColor | Color for filled areas (area charts). Defaults to colors.first. |
labelColor | Color for data point labels. |
positiveMaxColor | Color for the maximum positive value marker. |
positiveMinColor | Color for the minimum positive value marker. |
negativeMaxColor | Color for the maximum negative value marker. |
negativeMinColor | Color for the minimum negative value marker. |
Per-category color overrides
To color individual bars or segments, use colorsForCategory on ChartModel.
let model = ChartModel(
chartType: .column,
data: [[120, 90, 75, 140, 110]],
titlesForCategory: [["Jan", "Feb", "Mar", "Apr", "May"]],
colorsForCategory: [
0: [2: .red] // series 0, category index 2 is red
]
)
Shape-style gradients
Apply gradients or image fills to entire series or individual categories using view modifiers.
let gradient = LinearGradient(
colors: [.red, .green, .blue],
startPoint: .bottom,
endPoint: .top
)
ChartView(model)
.chartSeriesShapeStyle([1: AnyShapeStyle(gradient)])
.frame(width: 360, height: 220)
For per-category styling:
ChartView(model)
.chartCategoryShapeStyle([
0: [
0: AnyShapeStyle(LinearGradient(colors: [.red, .orange], startPoint: .bottom, endPoint: .top)),
1: AnyShapeStyle(Color.yellow)
]
])
.frame(width: 360, height: 220)
Data points
ChartPointAttributes controls the appearance of the dots drawn at each data value.
let pointAttrs = ChartPointAttributes(
isHidden: false,
diameter: 8,
strokeColor: .blue,
gap: 4
)
let seriesAttrs = ChartSeriesAttributes(
palette: ChartSeriesPalette(colors: [.blue]),
lineWidth: 2,
point: pointAttrs
)
| Property | Type | Default | Description |
|---|
isHidden | Bool | false | Hides or shows the point |
diameter | CGFloat | 7 | Point diameter in points (0–100) |
strokeColor | Color | .secondaryLabel | Outline color of the point |
gap | CGFloat | 2 | Minimum gap between adjacent points before they are hidden (0–100) |
Axes
Axis hierarchy
ChartAxisAttributes (base)
└── ChartNumericAxisAttributes (adds: isZeroBased, explicitMin/Max, formatter …)
└── ChartCategoryAxisAttributes (adds: labelLayoutStyle)
All axis attributes classes share a common set of sub-objects:
| Property | Type | Description |
|---|
baseline | ChartBaselineAttributes | The zero-line at the base of the chart |
gridlines | ChartGridlineAttributes | Horizontal or vertical grid rules |
labels | ChartLabelAttributes | Tick-mark labels along the axis |
titleLabel | ChartLabelAttributes | Appearance of the axis title text |
title | String? | Axis title string |
Configuring the numeric axis
let numericAxis = ChartNumericAxisAttributes()
numericAxis.isZeroBased = true // baseline starts at 0
numericAxis.explicitMin = -50 // override calculated minimum
numericAxis.explicitMax = 300 // override calculated maximum
numericAxis.abbreviatesLabels = true // "1.23k" instead of "1,234"
numericAxis.isMagnitudedDisplayed = true
numericAxis.gridlines.isHidden = false
numericAxis.gridlines.color = .gray.opacity(0.3)
numericAxis.gridlines.width = 1
numericAxis.labels.isHidden = false
numericAxis.labels.fontSize = 11
numericAxis.title = "Revenue (USD)"
let model = ChartModel(
chartType: .column,
data: [[200, 170, 165, 143, 166]],
titlesForCategory: [["Jan", "Feb", "Mar", "Apr", "May"]],
numericAxis: numericAxis
)
ChartNumericAxisAttributes key properties
| Property | Type | Default | Description |
|---|
isZeroBased | Bool | true | Starts the axis at zero when all values are positive or all negative |
explicitMin | CGFloat? | nil | Overrides the calculated axis minimum |
explicitMax | CGFloat? | nil | Overrides the calculated axis maximum |
abbreviatesLabels | Bool | false | Abbreviates large values (e.g. “1.2k”) |
isMagnitudedDisplayed | Bool | true | Includes the magnitude suffix (“k”, “M”) in abbreviated labels |
formatter | NumberFormatter | Decimal, 2 dp | Formatter applied to axis labels |
Configuring the category axis
ChartCategoryAxisAttributes extends ChartNumericAxisAttributes with a labelLayoutStyle property.
let catAxis = ChartCategoryAxisAttributes()
catAxis.labelLayoutStyle = .allOrNothing // show all labels or none
// or
catAxis.labelLayoutStyle = .range // show only first and last label
catAxis.labels.isHidden = false
catAxis.labels.fontSize = 10
catAxis.gridlines.isHidden = true
let model = ChartModel(
chartType: .line,
data: [[200, 170, 165, 143]],
titlesForCategory: [["Jan", "Feb", "Mar", "Apr"]],
categoryAxis: catAxis
)
Showing and hiding gridlines
// Hide all gridlines
model.numericAxis.gridlines.isHidden = true
// Show dashed gridlines
model.numericAxis.gridlines.isHidden = false
model.numericAxis.gridlines.dashPatternLength = 4
model.numericAxis.gridlines.dashPatternGap = 4
model.numericAxis.gridlines.color = .gray.opacity(0.4)
model.numericAxis.gridlines.width = 1
Labels
ChartLabelAttributes controls the appearance of text on both axis labels and axis titles.
let labelAttrs = ChartLabelAttributes(
color: .secondaryLabel,
fontSize: 11,
offset: 0,
isHidden: false
)
// Or with an explicit SwiftUI Font:
let labelAttrs = ChartLabelAttributes(
color: .primary,
font: .system(size: 11, weight: .medium)
)
| Property | Type | Default | Description |
|---|
color | Color | .tertiaryLabel | Label text color |
fontSize | CGFloat | 12 | Font size in points when font is not set (0–100) |
font | Font? | nil | Explicit SwiftUI font; takes priority over fontSize |
offset | CGFloat | 0 | Distance from the axis in points (–10 to 10) |
isHidden | Bool | false | Hides or shows the label |
backgroundColor | Color? | nil | Background fill behind the label |
Gridlines and baseline
ChartGridlineAttributes and its subclass ChartBaselineAttributes share the same dash-pattern-based line styling.
let gridline = ChartGridlineAttributes(
width: 1,
color: .gray.opacity(0.3),
dashPatternLength: 4,
dashPatternGap: 4,
isHidden: false
)
model.numericAxis.gridlines = gridline
| Property | Type | Default | Description |
|---|
width | CGFloat | 1 | Line width in points (0–20) |
color | Color | .secondaryFill | Line color |
dashPatternLength | CGFloat | 1 | Length of each dash segment (0–20) |
dashPatternGap | CGFloat | 0 for baseline, 3 for gridlines | Gap between dash segments (0–20) |
isHidden | Bool | false | Hides or shows the line |
ChartBaselineAttributes adds two read-only properties, value and position, that indicate the computed baseline value and its position in the chart’s coordinate space.
Custom axis label formatting
Use numericAxisLabelFormatHandler for full control over axis label strings.
let model = ChartModel(
chartType: .line,
data: [[1200, 3400, 2800, 4500]],
titlesForCategory: [["Q1", "Q2", "Q3", "Q4"]],
numericAxisLabelFormatHandler: { value, axisId in
guard axisId == .y else { return nil }
return "$\(Int(value / 1000))k"
}
)
Return nil from the handler to fall back to the default formatter.
Number of gridlines
// Set at init
let model = ChartModel(
chartType: .column,
data: [[100, 200, 150]],
numberOfGridlines: 5 // constrained to 2–20
)
// Change after init
model.numberOfGridlines = 4
Selection behavior
Selection mode
// Select one value in the active series and category
model.selectionMode = .single
// Select one value per series for the tapped category
model.selectionMode = .all
// Donut-only: allows multiple independent selections
// (set automatically for .donut charts)
model.selectionMode = .multiple
Programmatic selection
// Select category indices 0–6 in series 0
model.selections = [0: [0, 1, 2, 3, 4, 5, 6]]
// Select category 0 in both series
model.selections = [0: [0], 1: [0]]
// Clear the selection
model.selections = nil
Require a selection
Set selectionRequired = true to disallow the empty-selection state:
model.selectionRequired = true
Zoom and pan
// Enable all user interaction (pan + zoom)
model.userInteractionEnabled = true
model.scaleXEnabled = true
model.scaleYEnabled = true
// Snap to nearest data point while dragging
model.snapToPoint = true
// Set a programmatic zoom level
model.scaleX = 2.0 // range: 1.0–1024
model.scaleY = 1.5
// Center the viewport on a specific relative position
model.centerPosition = CGPoint(x: 0.5, y: 0.5)
Disable userInteractionEnabled when embedding a chart in a List row or an iOS Widget to prevent gesture conflicts.
Secondary value axis
Assign one or more series to a secondary Y axis on .line, .area, and .combo charts:
let model = ChartModel(
chartType: .line,
data: [
[200, 170, 165, 143, 166, 112, 110], // primary axis
[1.2, 0.8, 1.5, 0.9, 1.1, 1.4, 0.7] // secondary axis
],
titlesForCategory: [["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"]],
indexesOfSecondaryValueAxis: [1]
)
// Style the secondary axis independently
model.secondaryNumericAxis.labels.color = .orange
model.secondaryNumericAxis.title = "Ratio"