ChartAnimationEasing.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. //
  2. // ChartAnimationUtils.swift
  3. // Charts
  4. //
  5. // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
  6. // A port of MPAndroidChart for iOS
  7. // Licensed under Apache License 2.0
  8. //
  9. // https://github.com/danielgindi/Charts
  10. //
  11. import Foundation
  12. import CoreGraphics
  13. @objc
  14. public enum ChartEasingOption: Int
  15. {
  16. case linear
  17. case easeInQuad
  18. case easeOutQuad
  19. case easeInOutQuad
  20. case easeInCubic
  21. case easeOutCubic
  22. case easeInOutCubic
  23. case easeInQuart
  24. case easeOutQuart
  25. case easeInOutQuart
  26. case easeInQuint
  27. case easeOutQuint
  28. case easeInOutQuint
  29. case easeInSine
  30. case easeOutSine
  31. case easeInOutSine
  32. case easeInExpo
  33. case easeOutExpo
  34. case easeInOutExpo
  35. case easeInCirc
  36. case easeOutCirc
  37. case easeInOutCirc
  38. case easeInElastic
  39. case easeOutElastic
  40. case easeInOutElastic
  41. case easeInBack
  42. case easeOutBack
  43. case easeInOutBack
  44. case easeInBounce
  45. case easeOutBounce
  46. case easeInOutBounce
  47. }
  48. public typealias ChartEasingFunctionBlock = ((_ elapsed: TimeInterval, _ duration: TimeInterval) -> Double)
  49. internal func easingFunctionFromOption(_ easing: ChartEasingOption) -> ChartEasingFunctionBlock
  50. {
  51. switch easing
  52. {
  53. case .linear:
  54. return EasingFunctions.Linear
  55. case .easeInQuad:
  56. return EasingFunctions.EaseInQuad
  57. case .easeOutQuad:
  58. return EasingFunctions.EaseOutQuad
  59. case .easeInOutQuad:
  60. return EasingFunctions.EaseInOutQuad
  61. case .easeInCubic:
  62. return EasingFunctions.EaseInCubic
  63. case .easeOutCubic:
  64. return EasingFunctions.EaseOutCubic
  65. case .easeInOutCubic:
  66. return EasingFunctions.EaseInOutCubic
  67. case .easeInQuart:
  68. return EasingFunctions.EaseInQuart
  69. case .easeOutQuart:
  70. return EasingFunctions.EaseOutQuart
  71. case .easeInOutQuart:
  72. return EasingFunctions.EaseInOutQuart
  73. case .easeInQuint:
  74. return EasingFunctions.EaseInQuint
  75. case .easeOutQuint:
  76. return EasingFunctions.EaseOutQuint
  77. case .easeInOutQuint:
  78. return EasingFunctions.EaseInOutQuint
  79. case .easeInSine:
  80. return EasingFunctions.EaseInSine
  81. case .easeOutSine:
  82. return EasingFunctions.EaseOutSine
  83. case .easeInOutSine:
  84. return EasingFunctions.EaseInOutSine
  85. case .easeInExpo:
  86. return EasingFunctions.EaseInExpo
  87. case .easeOutExpo:
  88. return EasingFunctions.EaseOutExpo
  89. case .easeInOutExpo:
  90. return EasingFunctions.EaseInOutExpo
  91. case .easeInCirc:
  92. return EasingFunctions.EaseInCirc
  93. case .easeOutCirc:
  94. return EasingFunctions.EaseOutCirc
  95. case .easeInOutCirc:
  96. return EasingFunctions.EaseInOutCirc
  97. case .easeInElastic:
  98. return EasingFunctions.EaseInElastic
  99. case .easeOutElastic:
  100. return EasingFunctions.EaseOutElastic
  101. case .easeInOutElastic:
  102. return EasingFunctions.EaseInOutElastic
  103. case .easeInBack:
  104. return EasingFunctions.EaseInBack
  105. case .easeOutBack:
  106. return EasingFunctions.EaseOutBack
  107. case .easeInOutBack:
  108. return EasingFunctions.EaseInOutBack
  109. case .easeInBounce:
  110. return EasingFunctions.EaseInBounce
  111. case .easeOutBounce:
  112. return EasingFunctions.EaseOutBounce
  113. case .easeInOutBounce:
  114. return EasingFunctions.EaseInOutBounce
  115. }
  116. }
  117. internal struct EasingFunctions
  118. {
  119. internal static let Linear = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in return Double(elapsed / duration) }
  120. internal static let EaseInQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  121. var position = Double(elapsed / duration)
  122. return position * position
  123. }
  124. internal static let EaseOutQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  125. var position = Double(elapsed / duration)
  126. return -position * (position - 2.0)
  127. }
  128. internal static let EaseInOutQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  129. var position = Double(elapsed / (duration / 2.0))
  130. if position < 1.0
  131. {
  132. return 0.5 * position * position
  133. }
  134. return -0.5 * ((position - 1.0) * (position - 3.0) - 1.0)
  135. }
  136. internal static let EaseInCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  137. var position = Double(elapsed / duration)
  138. return position * position * position
  139. }
  140. internal static let EaseOutCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  141. var position = Double(elapsed / duration)
  142. position -= 1.0
  143. return (position * position * position + 1.0)
  144. }
  145. internal static let EaseInOutCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  146. var position = Double(elapsed / (duration / 2.0))
  147. if position < 1.0
  148. {
  149. return 0.5 * position * position * position
  150. }
  151. position -= 2.0
  152. return 0.5 * (position * position * position + 2.0)
  153. }
  154. internal static let EaseInQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  155. var position = Double(elapsed / duration)
  156. return position * position * position * position
  157. }
  158. internal static let EaseOutQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  159. var position = Double(elapsed / duration)
  160. position -= 1.0
  161. return -(position * position * position * position - 1.0)
  162. }
  163. internal static let EaseInOutQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  164. var position = Double(elapsed / (duration / 2.0))
  165. if position < 1.0
  166. {
  167. return 0.5 * position * position * position * position
  168. }
  169. position -= 2.0
  170. return -0.5 * (position * position * position * position - 2.0)
  171. }
  172. internal static let EaseInQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  173. var position = Double(elapsed / duration)
  174. return position * position * position * position * position
  175. }
  176. internal static let EaseOutQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  177. var position = Double(elapsed / duration)
  178. position -= 1.0
  179. return (position * position * position * position * position + 1.0)
  180. }
  181. internal static let EaseInOutQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  182. var position = Double(elapsed / (duration / 2.0))
  183. if position < 1.0
  184. {
  185. return 0.5 * position * position * position * position * position
  186. }
  187. else
  188. {
  189. position -= 2.0
  190. return 0.5 * (position * position * position * position * position + 2.0)
  191. }
  192. }
  193. internal static let EaseInSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  194. var position: TimeInterval = elapsed / duration
  195. return Double( -cos(position * Double.pi / 2) + 1.0 )
  196. }
  197. internal static let EaseOutSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  198. var position: TimeInterval = elapsed / duration
  199. return Double( sin(position * Double.pi / 2) )
  200. }
  201. internal static let EaseInOutSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  202. var position: TimeInterval = elapsed / duration
  203. return Double( -0.5 * (cos(Double.pi * position) - 1.0) )
  204. }
  205. internal static let EaseInExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  206. return (elapsed == 0) ? 0.0 : Double(pow(2.0, 10.0 * (elapsed / duration - 1.0)))
  207. }
  208. internal static let EaseOutExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  209. return (elapsed == duration) ? 1.0 : (-Double(pow(2.0, -10.0 * elapsed / duration)) + 1.0)
  210. }
  211. internal static let EaseInOutExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  212. if elapsed == 0
  213. {
  214. return 0.0
  215. }
  216. if elapsed == duration
  217. {
  218. return 1.0
  219. }
  220. var position: TimeInterval = elapsed / (duration / 2.0)
  221. if position < 1.0
  222. {
  223. return Double( 0.5 * pow(2.0, 10.0 * (position - 1.0)) )
  224. }
  225. position = position - 1.0
  226. return Double( 0.5 * (-pow(2.0, -10.0 * position) + 2.0) )
  227. }
  228. internal static let EaseInCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  229. var position = Double(elapsed / duration)
  230. return -(Double(sqrt(1.0 - position * position)) - 1.0)
  231. }
  232. internal static let EaseOutCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  233. var position = Double(elapsed / duration)
  234. position -= 1.0
  235. return Double( sqrt(1 - position * position) )
  236. }
  237. internal static let EaseInOutCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  238. var position: TimeInterval = elapsed / (duration / 2.0)
  239. if position < 1.0
  240. {
  241. return Double( -0.5 * (sqrt(1.0 - position * position) - 1.0) )
  242. }
  243. position -= 2.0
  244. return Double( 0.5 * (sqrt(1.0 - position * position) + 1.0) )
  245. }
  246. internal static let EaseInElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  247. if elapsed == 0.0
  248. {
  249. return 0.0
  250. }
  251. var position: TimeInterval = elapsed / duration
  252. if position == 1.0
  253. {
  254. return 1.0
  255. }
  256. var p = duration * 0.3
  257. var s = p / (2.0 * Double.pi) * asin(1.0)
  258. position -= 1.0
  259. return Double( -(pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p)) )
  260. }
  261. internal static let EaseOutElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  262. if elapsed == 0.0
  263. {
  264. return 0.0
  265. }
  266. var position: TimeInterval = elapsed / duration
  267. if position == 1.0
  268. {
  269. return 1.0
  270. }
  271. var p = duration * 0.3
  272. var s = p / (2.0 * Double.pi) * asin(1.0)
  273. return Double( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p) + 1.0 )
  274. }
  275. internal static let EaseInOutElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  276. if elapsed == 0.0
  277. {
  278. return 0.0
  279. }
  280. var position: TimeInterval = elapsed / (duration / 2.0)
  281. if position == 2.0
  282. {
  283. return 1.0
  284. }
  285. var p = duration * (0.3 * 1.5)
  286. var s = p / (2.0 * Double.pi) * asin(1.0)
  287. if position < 1.0
  288. {
  289. position -= 1.0
  290. return Double( -0.5 * (pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p)) )
  291. }
  292. position -= 1.0
  293. return Double( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p) * 0.5 + 1.0 )
  294. }
  295. internal static let EaseInBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  296. let s: TimeInterval = 1.70158
  297. var position: TimeInterval = elapsed / duration
  298. return Double( position * position * ((s + 1.0) * position - s) )
  299. }
  300. internal static let EaseOutBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  301. let s: TimeInterval = 1.70158
  302. var position: TimeInterval = elapsed / duration
  303. position -= 1.0
  304. return Double( position * position * ((s + 1.0) * position + s) + 1.0 )
  305. }
  306. internal static let EaseInOutBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  307. var s: TimeInterval = 1.70158
  308. var position: TimeInterval = elapsed / (duration / 2.0)
  309. if position < 1.0
  310. {
  311. s *= 1.525
  312. return Double( 0.5 * (position * position * ((s + 1.0) * position - s)) )
  313. }
  314. s *= 1.525
  315. position -= 2.0
  316. return Double( 0.5 * (position * position * ((s + 1.0) * position + s) + 2.0) )
  317. }
  318. internal static let EaseInBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  319. return 1.0 - EaseOutBounce(duration - elapsed, duration)
  320. }
  321. internal static let EaseOutBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  322. var position: TimeInterval = elapsed / duration
  323. if position < (1.0 / 2.75)
  324. {
  325. return Double( 7.5625 * position * position )
  326. }
  327. else if position < (2.0 / 2.75)
  328. {
  329. position -= (1.5 / 2.75)
  330. return Double( 7.5625 * position * position + 0.75 )
  331. }
  332. else if position < (2.5 / 2.75)
  333. {
  334. position -= (2.25 / 2.75)
  335. return Double( 7.5625 * position * position + 0.9375 )
  336. }
  337. else
  338. {
  339. position -= (2.625 / 2.75)
  340. return Double( 7.5625 * position * position + 0.984375 )
  341. }
  342. }
  343. internal static let EaseInOutBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
  344. if elapsed < (duration / 2.0)
  345. {
  346. return EaseInBounce(elapsed * 2.0, duration) * 0.5
  347. }
  348. return EaseOutBounce(elapsed * 2.0 - duration, duration) * 0.5 + 0.5
  349. }
  350. }