Selection & Interaction
Relevant source files
The following files were used as context for generating this wiki page:
- Sources/SwiftDitherKit/DitherSelection.swift
- Sources/SwiftDitherKit/SwiftDitherKit.docc/InteractionAndAccessibility.md
- Sources/SwiftDitherKit/DitherCartesianCharts.swift
- Sources/SwiftDitherKit/DitherPolarCharts.swift
- Sources/SwiftDitherKit/DitherAccessibility.swift
- Tests/SwiftDitherKitTests/DitherMathTests.swift
- Sources/SwiftDitherKit/DitherChartChrome.swift
SwiftDitherKit provides a robust system for user interaction and data selection across its various chart types, including Area, Line, Bar, Pie, and Radar charts. The system allows users to engage with dithered marks through tapping, dragging, and legend interaction, while maintaining state via SwiftUI bindings or internal logic.
Interaction is tightly coupled with accessibility, ensuring that semantic data remains available to assistive technologies even as visual representations utilize decorative dithered textures. This is achieved through Apple's chart accessibility descriptor APIs, which expose categories, values, and selection status.
Sources: InteractionAndAccessibility.md:3-9, DitherCartesianCharts.swift:316-338
Interaction Architecture
The interaction system is divided between the visual plot area and external chrome such as legends. Cartesian charts (Area, Line, Bar) utilize a dedicated interaction layer to handle gestures, while Polar charts (Pie, Radar) use specialized geometry for hit testing.
Component Breakdown
| Component | Responsibility |
|---|---|
| Interaction Layer | Captures DragGesture and SpatialTapGesture within the plot bounds. |
| Hit Tester | Determines which seriesID or sliceID corresponds to a screen coordinate. |
| Selection State | Manages Binding<String?> for the host view or internal @State. |
| Legend | Provides an alternative selection mechanism through interactive swatches. |
Sources: DitherCartesianCharts.swift:425-455, DitherPolarCharts.swift:319-354, InteractionAndAccessibility.md:14-20
Selection Flow
The following diagram illustrates how a user tap is processed into a selection change.
Hit Testing and Geometry
The library translates raw screen coordinates into data identifiers using geometric calculations specific to each chart kind.
Cartesian Hit Testing
For Area and Line charts, the selection targets the visible series polygon. Bar charts use exact grouped or stacked rectangles.
- Nearest Index: Finds the datum index closest to the horizontal
xcoordinate. - Series ID Detection: Uses
DitherSelectionHitTesterto identify which series polygon contains the specificCGPoint.
Sources: DitherCartesianCharts.swift:458-463, DitherMathTests.swift:115-164, InteractionAndAccessibility.md:18-20
Polar Hit Testing
Pie charts utilize wedge geometry, while Radar charts allow selection primarily through the legend.
- Pie Wedges: Hit testing for pie charts calculates the angle relative to the center and verifies if the radius falls between the inner and outer boundaries.
- Radar Spokes: Interaction layers for Radar charts track the hover index based on the angular proximity to spokes.
Sources: DitherPolarCharts.swift:343-354, DitherMathTests.swift:188-198
Selection Management
Selection state can be managed by the parent view using a Binding<String?> or internally by the chart component.
Binding and Normalization
When a selection binding is provided, the chart updates the host's state. If a selected ID becomes invalid (e.g., due to data changes), the DitherSelection.normalized function ensures the selection is cleared to prevent orphaned states.
// Example of external selection ownership
@State private var activeSeries: String?
DitherLineChart(
data: traffic,
series: channels,
selection: $activeSeries
)
Sources: InteractionAndAccessibility.md:5-12, DitherSelection.swift:3-13
Legend Interaction
The DitherLegend component provides a list of DitherLegendEntry items. Tapping a legend entry triggers selection for that specific series or slice. Tapping the currently active item again clears the selection.
Sources: DitherChartChrome.swift:12-42, DitherCartesianCharts.swift:335-337
Accessibility Integration
Interaction states are mirrored in the accessibility layer to support VoiceOver and other assistive technologies.
Semantic Mapping
The DitherAccessibility structure allows developers to provide localized labels for axes and summaries.
public struct DitherAccessibility: Hashable, Sendable {
public var title: String?
public var summary: String?
public var categoryAxisLabel: String?
public var valueAxisLabel: String?
}
Sources: DitherAccessibility.swift:4-10
Accessible Selection State
When a series or slice is selected, the chart's accessibility descriptor is updated to include this status in the summary provided to the user. For example, a Pie chart summary will append "[Label] is selected" when a specific slice is active.
Sources: DitherPieAccessibility.swift:37-45, Tests/SwiftDitherKitTests/DitherValueAndAccessibilityTests.swift:65-72
Motion and Feedback
Visual feedback for interaction is governed by the DitherMotion system, which provides haptic-like visual animations.
Feedback Characteristics
- Hover/Tap Animation: Uses a specific
timingCurvewith a duration of 0.14 seconds. - Selection Visuals: Selected items maintain full opacity (1.0) while unselected items in the legend or plot may be dimmed (e.g., 0.45 opacity).
- Tooltips: Cartesian and Pie charts present a
DitherTooltipduring hover/scrub interactions, showing the specific values for the active category or series.
Sources: DitherMotion.swift:7-19, DitherChartChrome.swift:51-53, DitherCartesianCharts.swift:415-422
Summary
Selection and interaction in SwiftDitherKit are designed to be intuitive yet technically precise. By combining custom geometric hit testing with standard SwiftUI gestures and Apple's accessibility frameworks, the library ensures that dithered charts are functional tools rather than just aesthetic elements. Key to this system is the normalization of IDs and the multi-layered feedback provided through tooltips, legends, and animations.