Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Pathを活用してSwift Chartsの限界を超えろ / create-graph-usi...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Fuya Yamada
July 14, 2023
Technology
1.7k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Pathを活用してSwift Chartsの限界を超えろ / create-graph-using-path
Fuya Yamada
July 14, 2023
More Decks by Fuya Yamada
See All by Fuya Yamada
iOS開発におけるCopilot For XcodeとCode Completion / copilot for xcode
fuyan777
1
3.3k
Other Decks in Technology
See All in Technology
誤解だらけの開発生産性 / Myths and Misconceptions about Developer Productivity
i35_267
2
810
AI時代の開発生産性は、個人技からチーム設計へ
moongift
PRO
4
2.4k
生成AI×AWS CDK×AWS FISで"振り返れる"ミニGameDayをつくろう
yoshimi0227
1
400
関数型の考えを TypeScript に持ち込んで、テストしやすい純粋関数を増やす / Pure at the Core, Effects at the Edge: Bringing Functional Thinking into TypeScript
kaminashi
2
130
知らん間に、回ってる
ming_ayami
0
720
オブザーバビリティ、本当に活用できてる? 〜API連携×生成AIで成熟度を自動評価〜
dmmsre
1
3.6k
Oracle Exadata Database Service on Cloud@Customer X11M (ExaDB-C@C) サービス概要
oracle4engineer
PRO
2
8.4k
公式ドキュメントの歩き方etc
coco_se
1
120
あなたの『Site』はどこですか? — xREという考え方
miyamu
0
1.2k
企業でAWS Organizationsを動かすための組織設計の考え方
nrinetcom
PRO
1
110
CIで使うClaude
iwatatomoya
0
290
人を動かすのは時間ではなく、納得感 〜新任EMが入社3ヶ月、組織を2回変えた話〜
kakehashi
PRO
3
270
Featured
See All Featured
WCS-LA-2024
lcolladotor
0
710
Being A Developer After 40
akosma
91
590k
Writing Fast Ruby
sferik
630
63k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
460
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
340
Code Review Best Practice
trishagee
74
20k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
260
GitHub's CSS Performance
jonrohan
1033
470k
How to build a perfect <img>
jonoalderson
1
5.8k
[SF Ruby Conf 2025] Rails X
palkan
2
1.2k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
340
Transcript
PathΛ׆༻ͯ͠ Swift ChartsͷݶքΛ͑Ζ גࣜձࣾZOZO ϒϥϯυιϦϡʔγϣϯ։ൃຊ෦ / ϑϩϯτΤϯυ෦ WEAR iOSϒϩοΫ ࢁా
෨ Copyright © ZOZO, Inc.
© ZOZO, Inc. גࣜձࣾZOZO ϒϥϯυιϦϡʔγϣϯ։ൃຊ෦ / ϑϩϯτΤϯυ෦ WEAR iOSϒϩοΫ ࢁా
෨ (Fuya Yamada) ελόʹߦͬͯɺۤΈʹ͑ͳ͕Β ҿΉίʔώʔ͕͖ ʢຊίίΞ͕ྑ͍ʣ
© ZOZO, Inc. ຊ͢͜ͱ PathΛ׆༻ͯ͠ Swift Chartsʹͳ͍άϥϑΛ࡞ͯ͠Έͨ ର Կ͔͠ΒSwiftUIΛѻ͏ਓ
© ZOZO, Inc. ΞδΣϯμ • Swift Chartsͷհ • Swift Chartsͷݶք
• PathΛ༻͍ͯݶքಥഁ͢Δํ๏ • Swift Chartsʹͳ͍άϥϑͷ࣮ྫ • ·ͱΊ 4
© ZOZO, Inc. Swift Chartsͷհ Swift Chartsͱʁ ◦ iOS 16͔Βར༻Ͱ͖Δ
SwiftUI ͷάϥϑඳըϥΠϒϥϦ ◦ ɺંΕઢɺࢄਤΛ͡Ίͱ͢Δ6छྨͷඳը͕Մೳ 5
© ZOZO, Inc. Swift Chartsͷհ 6 ຌྫͷՃ ਫฏઢͷදࣔ ͜ΜͳΧελϚΠζ͕Ͱ͖·͢
© ZOZO, Inc. Swift Chartsͷݶքʢ՝ʣ ԁάϥϑϨʔμʔνϟʔτඇରԠ 7 Swift ChartsͰαϙʔτ͞Ε͍ͯͳ͍άϥϑಠࣗͰ࡞Δඞཁ͕͋Δ https://chachart.net/radar
© ZOZO, Inc. PathΛ༻͍ͯݶքಥഁ͢Δํ๏ PathΛ׆༻ͯ͠άϥϑΛ࡞ Pathͱʁ ➔ ઢɺۂઢͳͲΛΈ߹Θͤͯෳࡶͳܗঢ়Λ࡞͢ΔͨΊͷߏମ ϝϦοτ ➔
දݱͷࣗ༝ͷߴ͞ 8 Path { path in ... } ChartsͰදݱͰ͖ͳ͔ͬͨϨΠΞτΛ࣮ݱՄೳ
© ZOZO, Inc. PathͷͰ͖Δ͜ͱ Path { path in path.move(to: CGPoint(x:
0, y: 0)) path.addLine(to: CGPoint(x: 100, y: 0)) } 9 path.closeSubpath() // ύεΛด͡Δ path.addArc( center: CGPoint(x: 100, y: 100), radius: 100, startAngle: .degrees(-90), endAngle: .degrees(0), clockwise: false ) ࢝↓
© ZOZO, Inc. ShapeϓϩτίϧΛར༻ ඳըՄೳͳਤܗΛఆٛ͢ΔͨΊͷΠϯλʔϑΣʔε PathͰԁάϥϑΛ࣮ 10 public protocol Shape
: Animatable, View { func path(in rect: CGRect) -> Path } Animatable ҙͷ͕มԽͨ࣌͠ɺ ΞχϝʔγϣϯΛద༻ path(in:)ϝιου ༩͑ΒΕͨCGRect (ඳըྖҬ) ʹඳը͢ΔPath
© ZOZO, Inc. PathͰԁάϥϑΛ࣮ 11 ࡞Γ͍ͨͷ ԁހͷ࡞ 3ͭͷΈ߹Θͤ ArcView
© ZOZO, Inc. struct ArcView: Shape { var startAngle: Double
var endAngle: Double var animatableData: Double { get { endAngle } set { endAngle = newValue } } func path(in rect: CGRect) -> Path { let rotationAdjustment = Angle(degrees: 90) let adjustedStartAngle = Angle(degrees: startAngle) - rotationAdjustment let adjustedEndAngle = Angle(degrees: endAngle) - rotationAdjustment return Path { p in p.addArc( center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: adjustedStartAngle, endAngle: adjustedEndAngle, clockwise: false ) p.addLine(to: CGPoint(x: rect.midX, y: rect.midY)) p.closeSubpath() } } } ArcViewͷ࣮ - શମ૾ 12 ArcView
© ZOZO, Inc. struct ArcView: Shape { var startAngle: Double
var endAngle: Double var animatableData: Double { get { endAngle } set { endAngle = newValue } } func path(in rect: CGRect) -> Path { let rotationAdjustment = Angle(degrees: 90) let adjustedStartAngle = Angle(degrees: startAngle) - rotationAdjustment let adjustedEndAngle = Angle(degrees: endAngle) - rotationAdjustment return Path { p in p.addArc( center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: adjustedStartAngle, endAngle: adjustedEndAngle, clockwise: false ) p.addLine(to: CGPoint(x: rect.midX, y: rect.midY)) p.closeSubpath() } } } ArcViewͷ࣮ AnimatableData ϓϩύςΟ e.g. endAngleʢऴྃ֯ʣΛ ࢦఆ͢ΔͱArcViewͷׂ߹͕ ૿Ճ͢ΔΞχϝʔγϣϯ var animatableData: Double { get { endAngle } set { endAngle = newValue } } 13
© ZOZO, Inc. struct ArcView: Shape { var startAngle: Double
var endAngle: Double var animatableData: Double { get { endAngle } set { endAngle = newValue } } func path(in rect: CGRect) -> Path { let rotationAdjustment = Angle(degrees: 90) let adjustedStartAngle = Angle(degrees: startAngle) - rotationAdjustment let adjustedEndAngle = Angle(degrees: endAngle) - rotationAdjustment return Path { p in p.addArc( center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: adjustedStartAngle, endAngle: adjustedEndAngle, clockwise: false ) p.addLine(to: CGPoint(x: rect.midX, y: rect.midY)) p.closeSubpath() } } } ArcViewͷ࣮ 0Λ্෦ʹ͢ΔͨΊʹ ֯ௐ let rotationAdjustment = Angle(degrees: 90) let adjustedStartAngle = Angle(degrees: startAngle) - rotationAdjustment let adjustedEndAngle = Angle(degrees: endAngle) - rotationAdjustment 14 0° 0°
© ZOZO, Inc. struct ArcView: Shape { var startAngle: Double
var endAngle: Double var animatableData: Double { get { endAngle } set { endAngle = newValue } } func path(in rect: CGRect) -> Path { let rotationAdjustment = Angle(degrees: 90) let adjustedStartAngle = Angle(degrees: startAngle) - rotationAdjustment let adjustedEndAngle = Angle(degrees: endAngle) - rotationAdjustment return Path { p in p.addArc ( center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: adjustedStartAngle, endAngle: adjustedEndAngle, clockwise: false ) p.addLine(to: CGPoint(x: rect.midX, y: rect.midY)) p.closeSubpath() } } } ArcViewͷ࣮ ԁހͷඳը addArc + addLine & close return Path { p in p.addArc ( center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: adjustedStartAngle, endAngle: adjustedEndAngle, clockwise: false ) p.addLine(to: CGPoint(x: rect.midX, y: rect.midY)) p.closeSubpath() } 15
© ZOZO, Inc. PathͰԁάϥϑΛ࣮ 16 ԁάϥϑ struct PieChartView: View {
var body: some View { ZStack { ArcView(startAngle: 0, endAngle: 360) .fill(Color("green")) ArcView(startAngle: 0, endAngle: 250) .fill(Color("blue")) ArcView(startAngle: 0, endAngle: 140) .fill(Color("red")) } } }
© ZOZO, Inc. PathͰԁάϥϑΛ࣮ 17 ςΩετࠞͥͯ ͜Μͳ͜ͱͰ͖Δ
© ZOZO, Inc. ͞ΒʹPathͰϨʔμʔνϟʔτ࣮Մೳ • addLine(to:), move(to:) ͷΈ • ଟ֯ܗͷ֤Λܭࢉ͠ɺ
Λͭͳ͛ͯଟ֯ܗΛඳը 18
© ZOZO, Inc. ͞ΒʹPathͰϨʔμʔνϟʔτ࣮Մೳ 19 ϕʔεͷViewͷ࡞ํ๏Λ ͬ͘͟Γ͝հ PolygonShape
© ZOZO, Inc. struct PolygonShape: Shape { let sides: Int
// ลͷ func path(in rect: CGRect) -> Path { let centerX = rect.width / 2 let centerY = rect.height / 2 let radius = min(rect.width, rect.height) / 2 let angle = .pi * 2 / Double(sides) let offsetAngle = -(Double.pi / 2) // 0Λ্෦ʹ͢ΔͨΊʹ֯ௐ return Path { path in for index in 0..<sides { let currentAngle = angle * Double(index) + offsetAngle let x = centerX + cos(currentAngle) * radius let y = centerY + sin(currentAngle) * radius if index == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) } } path.closeSubpath() } } } Ϩʔμʔνϟʔτ - શମ૾ 20
© ZOZO, Inc. struct PolygonShape: Shape { let sides: Int
// ลͷ func path(in rect: CGRect) -> Path { let centerX = rect.width / 2 let centerY = rect.height / 2 let radius = min(rect.width, rect.height) / 2 let angle = .pi * 2 / Double(sides) let offsetAngle = -(Double.pi / 2) // 0Λ্෦ʹ͢ΔͨΊʹ֯ௐ return Path { path in for index in 0..<sides { let currentAngle = angle * Double(index) + offsetAngle let x = centerX + cos(currentAngle) * radius let y = centerY + sin(currentAngle) * radius if index == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) } } path.closeSubpath() } } } Ϩʔμʔνϟʔτ - શମ૾ 21
© ZOZO, Inc. struct PolygonShape: Shape { let sides: Int
// ลͷ func path(in rect: CGRect) -> Path { let centerX = rect.width / 2 let centerY = rect.height / 2 let radius = min(rect.width, rect.height) / 2 let angle = .pi * 2 / Double(sides) let offsetAngle = -(Double.pi / 2) // 0Λ্෦ʹ͢ΔͨΊʹ֯ௐ return Path { path in for index in 0..<sides { let currentAngle = angle * Double(index) + offsetAngle let x = centerX + cos(currentAngle) * radius let y = centerY + sin(currentAngle) * radius if index == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) } } path.closeSubpath() } } } Ϩʔμʔνϟʔτ - શମ૾ 22 ลͷΛఆٛ let sides: Int // ลͷ
© ZOZO, Inc. struct PolygonShape: Shape { let sides: Int
// ลͷ func path(in rect: CGRect) -> Path { let centerX = rect.width / 2 let centerY = rect.height / 2 let radius = min(rect.width, rect.height) / 2 let angle = .pi * 2 / Double(sides) let offsetAngle = -(Double.pi / 2) // 0Λ্෦ʹ͢ΔͨΊʹ֯ௐ return Path { path in for index in 0..<sides { let currentAngle = angle * Double(index) + offsetAngle let x = centerX + cos(currentAngle) * radius let y = centerY + sin(currentAngle) * radius if index == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) } } path.closeSubpath() } } } Ϩʔμʔνϟʔτ - શମ૾ 23
© ZOZO, Inc. struct PolygonShape: Shape { let sides: Int
// ลͷ func path(in rect: CGRect) -> Path { let centerX = rect.width / 2 let centerY = rect.height / 2 let radius = min(rect.width, rect.height) / 2 let angle = .pi * 2 / Double(sides) let offsetAngle = -(Double.pi / 2) // 0Λ্෦ʹ͢ΔͨΊʹ֯ௐ return Path { path in for index in 0..<sides { let currentAngle = angle * Double(index) + offsetAngle let x = centerX + cos(currentAngle) * radius let y = centerY + sin(currentAngle) * radius if index == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) } } path.closeSubpath() } } } Ϩʔμʔνϟʔτ - શମ૾ 24 Ҿ CGRect ͔Βத৺ɺܘɺ֯ͷࢉग़ let centerX = rect.width / 2 let centerY = rect.height / 2 let radius = min(rect.width, rect.height) / 2 let angle = .pi * 2 / Double(sides) let offsetAngle = -(Double.pi / 2)
© ZOZO, Inc. struct PolygonShape: Shape { let sides: Int
// ลͷ func path(in rect: CGRect) -> Path { let centerX = rect.width / 2 let centerY = rect.height / 2 let radius = min(rect.width, rect.height) / 2 let angle = .pi * 2 / Double(sides) let offsetAngle = -(Double.pi / 2) // 0Λ্෦ʹ͢ΔͨΊʹ֯ௐ return Path { path in for index in 0..<sides { let currentAngle = angle * Double(index) + offsetAngle let x = centerX + cos(currentAngle) * radius let y = centerY + sin(currentAngle) * radius if index == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) } } path.closeSubpath() } } } Ϩʔμʔνϟʔτ - શମ૾ 25
© ZOZO, Inc. struct PolygonShape: Shape { let sides: Int
// ลͷ func path(in rect: CGRect) -> Path { let centerX = rect.width / 2 let centerY = rect.height / 2 let radius = min(rect.width, rect.height) / 2 let angle = .pi * 2 / Double(sides) let offsetAngle = -(Double.pi / 2) // 0Λ্෦ʹ͢ΔͨΊʹ֯ௐ return Path { path in for index in 0..<sides { let currentAngle = angle * Double(index) + offsetAngle let x = centerX + cos(currentAngle) * radius let y = centerY + sin(currentAngle) * radius if index == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) } } path.closeSubpath() } } } Ϩʔμʔνϟʔτ - શମ૾ 26 ֤ͷ֯Λܭࢉ ࠷ॳͷͳΒύεͷ։࢝Λઃఆ ͦΕҎ֎ͳΒઢΛҾ͘ return Path { path in for index in 0..<sides { let currentAngle = angle * Double(index) + offsetAngle let x = centerX + cos(currentAngle) * radius let y = centerY + sin(currentAngle) * radius if index == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) } } path.closeSubpath() }
© ZOZO, Inc. ͞ΒʹPathͰϨʔμʔνϟʔτ࣮Մೳ 27 PolygonShape ϕʔεͷView
© ZOZO, Inc. ͡Ό͋PathͰάϥϑͷ࡞ʹݶք͋Δͷʁʁ 2DͷඳըքͰݶքແ͍ʂʁʢFuyaௐʣ 28
© ZOZO, Inc. ·ͱΊ Swift ChartsͰαϙʔτ͞Ε͍ͯͳ͍άϥϑ PathΛ࣮ͬͯ͢Δ͜ͱ͕Մೳ 29 ৄ͍࣮͠ํ๏ͪ͜Β͔Β
https://github.com/Fuyan777/charts-sample
None