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
Digital Credentials API × OpenID4VP ブラウザ完結型本人確認の実装知見(OAuth/OIDC Numa (Immersion) Workshop 2026)
oidfj
PRO
0
330
医療の現場を変革に挑戦した半年間の軌跡 - PythonとAIで現場を変える / From Code to Care
soudai
PRO
1
640
みてねにおけるAI-DLC導入活動とAIドリブン開発の現在地/JAWS-UG AI-DLC #2
isaoshimizu
2
270
ハッカソンで入賞した話 @ Findy LT
asari194617
0
1.5k
AIエージェントのためのデータ設計
daiz21
0
520
Sansan Engineering Unit 紹介資料
sansan33
PRO
1
5k
AI駆動開発をチームに根付かせる - 「1行も書かない」チームがHarnessを育てた1年 -
kenichirokimura
6
3.3k
Microsoft MVP プログラムを紹介するから目指す人増えてくれ
tsubakimoto_s
0
140
「面白い!」を信じ抜け。激動の時代を貫く、オンリーワン・エンジニアの条件
kizawa2020
2
380
顧客の要望は2次情報である 〜アンテナを張るFDEの構造論〜
noriakioji
5
1k
Windows の互換機能 - 古いプログラムはなぜ動作できるのか
murachiakira
PRO
0
130
OpenID for Verifiable Credentials 実装から見えた相互運用性確保までの道のり(OAuth/OIDC Numa (Immersion) Workshop 2026)
oidfj
PRO
0
360
Featured
See All Featured
Side Projects
sachag
455
43k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
480
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
390
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
Agile that works and the tools we love
rasmusluckow
331
22k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
300
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.3k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Ruling the World: When Life Gets Gamed
codingconduct
0
310
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