Skip to main content

charts-3d

3D chart visualization with Swift Charts using Chart3D, SurfacePlot, interactive pose control, and surface styling — plus a 2D Swift Charts construction reference (marks, axes, selection, SectorMark, scrollable charts). Use when creating data visualizations with Swift Charts.

跳到安装

来源信息

仓库
rshankras/claude-code-apple-skills
最近来源活动
2026年7月16日 14:28
检测到的 SKILL.md 语言
英语
星标
753
分支
71

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
charts-3d
description
3D chart visualization with Swift Charts using Chart3D, SurfacePlot, interactive pose control, and surface styling — plus a 2D Swift Charts construction reference (marks, axes, selection, SectorMark, scrollable charts). Use when creating data visualizations with Swift Charts.
allowed-tools
["Read","Glob","Grep"]
last_verified
2026-07-16T00:00:00.000Z
review_by
2027-06-22T00:00:00.000Z
os_version
iOS 27 / macOS 27
# 3D Charts with Swift Charts Create 3D data visualizations using `Chart3D` and `SurfacePlot`. Covers math-driven surfaces, data-driven surfaces, interactive camera pose control, surface styling, and camera projection modes. ## When This Skill Activates Use this skill when the user: - Wants to create a 3D chart or 3D data visualization - Asks about `Chart3D`, `SurfacePlot`, or 3D surface plots - Needs to visualize a mathematical function as a 3D surface - Wants interactive drag-to-rotate on a 3D chart - Asks about 3D chart camera angles, pose, or projection - Needs to style 3D surfaces with gradients or height-based coloring - Wants to render multiple surfaces in a single 3D chart - Asks about data-driven 3D plots from an array of points - Needs the 2D Swift Charts API layer: marks, axes, series styling, selection, SectorMark pies/donuts, or scrollable charts ## Decision Tree ``` What 3D chart feature do you need? | +-- Visualize a math function f(x, y) -> z | +-- Use SurfacePlot(x:y:z:function:) | +-- Visualize data points as a surface | +-- Use Chart3D(data) { point in SurfacePlot(...) } | +-- Interactive drag-to-rotate | +-- Bind pose: .chart3DPose($pose) with @State var pose: Chart3DPose | +-- Fixed viewing angle (no interaction) | +-- Read-only pose: .chart3DPose(Chart3DPose.front) or custom | +-- Style the surface color | +-- Solid color -> .foregroundStyle(Color.blue) | +-- Gradient -> .foregroundStyle(LinearGradient(...)) | +-- Height-based -> .foregroundStyle(.heightBased(gradient, yRange:)) | +-- Normal-based -> .foregroundStyle(.normalBased) | +-- Camera projection | +-- Perspective (depth) -> .chart3DCameraProjection(.perspective) | +-- Orthographic (flat) -> .chart3DCameraProjection(.orthographic) | +-- System default -> .chart3DCameraProjection(.automatic) | +-- Multiple surfaces in one chart +-- Place multiple SurfacePlot calls inside a single Chart3D { } ``` ## API Availability | API | Minimum Version | Import | Notes | |-----|----------------|--------|-------| | `Chart3D` | iOS 26 / macOS 26 | `Charts` | Main 3D chart container | | `SurfacePlot` | iOS 26 / macOS 26 | `Charts` | 3D surface mark | | `Chart3DPose` | iOS 26 / macOS 26 | `Charts` | Viewing angle control | | `Chart3DCameraProjection` | iOS 26 / macOS 26 | `Charts` | `.automatic`, `.perspective`, `.orthographic` | | `Chart3DSurfaceStyle` | iOS 26 / macOS 26 | `Charts` | `.heightBased`, `.normalBased` | ## Quick Start ### Math-Driven Surface Render a surface from a function `f(x, y) -> z`: ```swift import SwiftUI import Charts struct WaveSurfaceView: View { var body: some View { Chart3D { SurfacePlot( x: "X", y: "Height", z: "Z", function: { x, z in sin(x) * cos(z) } ) .foregroundStyle(.blue) } } } ``` ### Data-Driven Surface Render a surface from an array of data points: ```swift import SwiftUI import Charts struct DataPoint: Identifiable { let id = UUID() let x: Double let y: Double let z: Double } struct DataSurfaceView: View { let points: [DataPoint] var body: some View { Chart3D(points) { point in SurfacePlot( x: .value("X", point.x), y: .value("Height", point.y), z: .value("Z", point.z) ) } } } ``` ### Interactive Rotation Allow the user to drag to rotate the chart: ```swift import SwiftUI import Charts struct InteractiveChartView: View { @State private var pose = Chart3DPose.default var body: some View { Chart3D { SurfacePlot( x: "X", y: "Height", z: "Z", function: { x, z in sin(x) * cos(z) } ) .foregroundStyle(.blue) } .chart3DPose($pose) } } ``` ## Surface Styling Patterns ### Solid Color ```swift SurfacePlot(x: "X", y: "Y", z: "Z", function: { x, z in x * z }) .foregroundStyle(.blue) ``` ### Linear Gradient ```swift SurfacePlot(x: "X", y: "Y", z: "Z", function: { x, z in x * z }) .foregroundStyle( LinearGradient( colors: [.blue, .green, .yellow], startPoint: .bottom, endPoint: .top ) ) ``` ### Height-Based Surface Style Color the surface based on height values, mapping a gradient across the y-axis range: ```swift SurfacePlot(x: "X", y: "Y", z: "Z", function: { x, z in sin(x) * cos(z) }) .foregroundStyle( Chart3DSurfaceStyle.heightBased( Gradient(colors: [.blue, .cyan, .green, .yellow, .red]), yRange: -1...1 ) ) ``` ### Normal-Based Surface Style Color based on surface normals, giving a lighting-aware appearance: ```swift SurfacePlot(x: "X", y: "Y", z: "Z", function: { x, z in sin(x) * cos(z) }) .foregroundStyle(Chart3DSurfaceStyle.normalBased) ``` ### Surface Roughness Control surface shininess (0 = reflective, 1 = matte): ```swift SurfacePlot(x: "X", y: "Y", z: "Z", function: { x, z in sin(x) * cos(z) }) .foregroundStyle(.blue) .roughness(0.3) ``` ## Interactive Pose Control ### Preset Poses `Chart3DPose` provides built-in presets for common viewing angles: ```swift .chart3DPose(.default) // Standard 3/4 angle .chart3DPose(.front) // Viewing from front .chart3DPose(.back) // Viewing from back .chart3DPose(.top) // Top-down view .chart3DPose(.bottom) // Bottom-up view .chart3DPose(.right) // Right side view .chart3DPose(.left) // Left side view ``` ### Custom Pose Specify exact azimuth (horizontal rotation) and inclination (vertical tilt): ```swift .chart3DPose( Chart3DPose(azimuth: .degrees(45), inclination: .degrees(30)) ) ``` ### Anti-Patterns ```swift // ❌ Passing a literal where a binding is needed for interactivity .chart3DPose(.default) // This is read-only; drag gestures will not work // ✅ Use a @State binding for interactive rotation @State private var pose = Chart3DPose.default // ... .chart3DPose($pose) ``` ## Camera Projection Control how 3D depth is rendered: ```swift Chart3D { SurfacePlot(x: "X", y: "Y", z: "Z", function: { x, z in sin(x) * cos(z) }) .foregroundStyle(.blue) } .chart3DCameraProjection(.perspective) // Objects farther away appear smaller // .chart3DCameraProjection(.orthographic) // No perspective distortion // .chart3DCameraProjection(.automatic) // System decides ``` ## Multiple Surfaces Render multiple surfaces in a single chart for comparison: ```swift import SwiftUI import Charts struct ComparisonChartView: View { @State private var pose = Chart3DPose.default var body: some View { Chart3D { SurfacePlot( x: "X", y: "Wave A", z: "Z", function: { x, z in sin(x) * cos(z) } ) .foregroundStyle(.blue.opacity(0.8)) SurfacePlot( x: "X", y: "Wave B", z: "Z", function: { x, z in cos(x) * sin(z) } ) .foregroundStyle(.red.opacity(0.8)) } .chart3DPose($pose) .chart3DCameraProjection(.perspective) } } ``` ## Complete Example A full-featured 3D chart with height-based coloring, interactive rotation, and perspective projection: ```swift import SwiftUI import Charts struct TerrainView: View { @State private var pose = Chart3DPose( azimuth: .degrees(30), inclination: .degrees(25) ) var body: some View { VStack { Text("Terrain Visualization") .font(.headline) Chart3D { SurfacePlot( x: "Longitude", y: "Elevation", z: "Latitude", function: { x, z in let distance = sqrt(x * x + z * z) return sin(distance) / max(distance, 0.1) } ) .foregroundStyle( Chart3DSurfaceStyle.heightBased( Gradient(colors: [ .blue, .cyan, .green, .yellow, .orange, .red ]), yRange: -0.5...1.0 ) ) .roughness(0.4) } .chart3DPose($pose) .chart3DCameraProjection(.perspective) } .padding() } } ``` ## Chart Design Fundamentals (WWDC22) These apply to every chart you build — 2D or 3D. The pillars: **focused, approachable, accessible**. - **Pick marks by goal**: bars for patterns, ranges, and individual values; points for spotting outliers; lines for rates of change. - **Test with real, noisy data early** — placeholder sine waves hide layout failures. Design the edge cases explicitly (e.g., gaps in a line chart where data is missing). - **~4 horizontal gridlines** is a good baseline; pick intuitive intervals — multiples of 20 for counts, multiples of 7 for day-based axes. - **Descriptive takeaway title** ("Total Sales: 1,234 Pancakes"), not a generic label ("Sales") — and give the chart surrounding context. - **Touch targets stretch to full chart height** — a tap anywhere in a bar's column selects it, not just the drawn pixels. - Support **touch, keyboard, Voice Control, Switch Control, and VoiceOver equally** — every interaction needs a non-pointer path. - **Color enhances, never solely conveys** — differentiate series with symbols/shapes first, color second. Verify contrast in Dark, Light, and Increase Contrast, and balance saturation so no series visually outweighs the others. - **Every visual encoding needs a non-visual representation** — per-mark VoiceOver labels and an Audio Graph descriptor; Swift Charts provides both by default, so don't break them with custom drawing. Custom-drawn charts implement them by hand — see "Audio Graphs: AXChartDescriptor" below. ## Swift Charts Construction Reference (2D) The design fundamentals above apply to every chart; this is the API layer for standard 2D charts (iOS 16+ unless noted; selection, SectorMark, and scrolling are iOS 17+). ### Marks Compose A `Chart` is a composition of marks — `BarMark`, `LineMark`, `PointMark`, `AreaMark`, `RuleMark`, `RectangleMark`. The `.value("Label", v)` factory arguments do double duty: they bind data AND drive the automatic axes and legend, so label them meaningfully: ```swift Chart(salesData) { sale in // Identifiable data — no explicit ForEach needed BarMark( x: .value("Day", sale.day, unit: .day), // unit: .day buckets temporal values per day y: .value("Sales", sale.count) ) } ``` - Transpose a chart by swapping the x/y value pairs — horizontal bars need no other change. - `unit:` (`.day`, `.month`, `.hour`) controls temporal bucketing; omit it and every timestamp is its own position. ### Series: Style + Symbol, Never Color Alone `.foregroundStyle(by:)` splits marks into series; pair it with `.symbol(by:)` so series stay distinguishable without color (WWDC22): ```swift Chart(data) { point in LineMark(x: .value("Day", point.day), y: .value("Sales", point.sales)) .foregroundStyle(by: .value("City", point.city)) .symbol(by: .value("City", point.city)) } ``` - Remap series colors with `.chartForegroundStyleScale(["Cupertino": .indigo, "San Francisco": .teal])`. - `.position(by: .value("City", point.city))` converts stacked bars into grouped bars. ### Pin Scales for Stability Pin scales so a filtered dataset doesn't make the whole chart jump: ```swift .chartYScale(domain: 0...maxExpectedSales) .chartXScale(domain: startDate...endDate) ``` ### Composing Statistics into a Chart Marks compose freely, so summary statistics are just more marks: ```swift Chart { ForEach(data) { point in AreaMark( // min–max band x: .value("Day", point.day), yStart: .value("Min", point.min), yEnd: .value("Max", point.max) ) .opacity(0.3) LineMark(x: .value("Day", point.day), y: .value("Average", point.average)) } RuleMark(y: .value("Overall", overallAverage)) // overall average line .foregroundStyle(.secondary) .annotation(position: .top, alignment: .leading) { Text("Avg: \(overallAverage, format: .number.precision(.fractionLength(0)))")
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看