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
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
なぜ私たちのSREプラクティスはなかなか機能しないのか 〜システムより先に組織を見る〜 / Why our SRE practices aren't really working
vtryo
4
4k
「守りたい体験」を渡すだけで E2E を生成させられるようになった話
hinac0
0
170
「ちゃんとやっている」は独りよがりだった ― 不安に寄り添うインシデント対応へ / Towards incident response that addresses anxieties
chmikata
1
5.9k
ゴールデンパスは敷いただけでは道にならない ─ 企画部門のエンジニアが技術標準を事業価値に変えるまで
mhrtech
1
200
Amazon EVS で VCF 9.0 / 9.1 のサポート開始まとめ
mtoyoda
0
310
LLM/Agent評価:トップ営業の発言を「正解」にする 〜暗黙的正解による評価を営業資産に変える〜
takkuhiro
1
230
タスクの複雑さでモデルを選ぶ ── Thompson Samplingで動かす“トークン/コスト最適化
satohy0323
0
550
Alphaモジュール使っていいのかい!?いけないのかい!?どっちなんだいっ!?
watany
1
270
ファミコンでPHPを動かす / PHP on the Famicom
tomzoh
2
340
Oracle Exadata Database Service on Cloud@Customer X11M (ExaDB-C@C) サービス概要
oracle4engineer
PRO
2
8.4k
Network Firewallやっていき!
news_it_enj
0
170
あなたの『Site』はどこですか? — xREという考え方
miyamu
0
1.2k
Featured
See All Featured
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.4k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
150
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
72
40k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
370
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
240
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
210
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.4k
Designing for Performance
lara
611
70k
For a Future-Friendly Web
brad_frost
183
10k
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