teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

Animation GIFを追加

2020/09/17 09:00

投稿

TsukubaDepot
TsukubaDepot

スコア5086

answer CHANGED
@@ -43,6 +43,9 @@
43
43
  この実装はまだ中途半端で、たとえばスケールファクターを変更した場合には、赤丸が残ったまま追従しないなどの問題もありますが、それは追々解決していただければと思います。
44
44
 
45
45
  ##描画完了した瞬間に、指定したデータに円弧を書かせる方法
46
+
47
+ ![イメージ説明](973b638f1f94c218e25972b7368dcc83.gif)
48
+
46
49
  [https://github.com/danielgindi/Charts/blob/master/ChartsDemo-iOS/Swift/DemoBaseViewController.swift
47
50
  ](https://github.com/danielgindi/Charts/blob/master/ChartsDemo-iOS/Swift/DemoBaseViewController.swift)
48
51
 

2

コメントを受けた問題の解決

2020/09/17 09:00

投稿

TsukubaDepot
TsukubaDepot

スコア5086

answer CHANGED
@@ -42,43 +42,59 @@
42
42
 
43
43
  この実装はまだ中途半端で、たとえばスケールファクターを変更した場合には、赤丸が残ったまま追従しないなどの問題もありますが、それは追々解決していただければと思います。
44
44
 
45
- ##指定したポイントに円弧を描くためのコードの
45
+ ##描画完了した瞬間に、指定したデータに円弧を書かせる方法
46
+ [https://github.com/danielgindi/Charts/blob/master/ChartsDemo-iOS/Swift/DemoBaseViewController.swift
47
+ ](https://github.com/danielgindi/Charts/blob/master/ChartsDemo-iOS/Swift/DemoBaseViewController.swift)
48
+
49
+ github 上のサンプルに対して加えた変更なのでちょっと複雑な流れになっています。
50
+
51
+ このサンプルの場合、delegate が親クラスとなっているため、途中でダウンキャストを行なっていますが、そうでない場合にはもっとシンプルに記述できると思われます。
52
+
53
+ 解決のヒントになったissue:
54
+ - [(v3.0 + Swift3.0)ChartView highlightValueWithX not working #1495](https://github.com/danielgindi/Charts/issues/1495)
55
+
46
56
  ```Swift
47
57
  // 表示が完全に止まったら呼び出される delegate
58
+ // https://github.com/danielgindi/Charts/issues/1495
48
59
  func chartView(_ chartView: ChartViewBase, animatorDidStop animator: Animator) {
49
- print(#function)
50
- //chartView.highlightValue(Highlight(x: values[19].x, y: values[19].y, dataSetIndex: 0), callDelegate: true)
60
+ // chartView に保存されているデータセットのうち、1つ目を取り出す
51
61
  if let set1 = chartView.data?.getDataSetByIndex(0) {
62
+ // 取り出したデータセットのうち、19番目を取り出す
52
63
  if let val = set1.entryForIndex(19) {
53
64
  // ハイライトさせる
54
65
  chartView.highlightValue(Highlight(x: val.x, y: val.y, dataSetIndex: 0), callDelegate: true)
55
66
 
56
- // ここで得られるハイライト座標には、View 内部での座標(xPx, yPx)が代入されないため、円弧を書くための座標を算出することができない
57
- let hightlight = Highlight(x: val.x, y: val.y, dataSetIndex: 0)
58
67
 
68
+ // delegate が親クラスになっているため、view を一度子クラスの LineChartView にダウンキャストする
69
+ if let view = chartView as? LineChartView {
70
+ // 生データと画面上のデータを変換させる
71
+ let transformer = view.getTransformer(forAxis: view.leftAxis.axisDependency)
59
- // 点滅させる
72
+ // ここで得られた値が生データ
60
- // ** 以下のコードを実施しても、xPx, yPx が nan のため正しく表示されない
73
+ let pt = transformer.pixelForValues(x: val.x, y: val.y)
74
+
61
- // 以前のアニメーションを消す
75
+ // 以前のアニメーションを消す
62
- circleLayer?.removeFromSuperlayer()
76
+ circleLayer?.removeFromSuperlayer()
63
-
77
+
64
- // 透明度のアニメーションを設定する。
78
+ // 透明度のアニメーションを設定する。
65
- // alpha ではなく、opacity であることに注意。
79
+ // alpha ではなく、opacity であることに注意。
66
- let animation = CAKeyframeAnimation(keyPath: "opacity")
80
+ let animation = CAKeyframeAnimation(keyPath: "opacity")
67
- animation.duration = 1
81
+ animation.duration = 1
68
- animation.keyTimes = [0.0, 0.5, 1.0]
82
+ animation.keyTimes = [0.0, 0.5, 1.0]
69
- animation.values = [1.0, 0.00, 1.0]
83
+ animation.values = [1.0, 0.00, 1.0]
70
- animation.repeatCount = .greatestFiniteMagnitude
84
+ animation.repeatCount = .greatestFiniteMagnitude
71
-
85
+
72
- // タップされた座標を中心として円形を作る
86
+ // タップされた座標を中心として円形を作る
73
- circleLayer = CAShapeLayer()
87
+ circleLayer = CAShapeLayer()
74
- let circlePath = UIBezierPath(arcCenter: CGPoint(x: highlight.xPx, y: highlight.yPx), radius: 20, startAngle: 0, endAngle: .pi*2, clockwise: true)
88
+ let circlePath = UIBezierPath(arcCenter: CGPoint(x: pt.x, y: pt.y), radius: 20, startAngle: 0, endAngle: .pi*2, clockwise: true)
75
- circleLayer?.path = circlePath.cgPath
89
+ circleLayer?.path = circlePath.cgPath
76
- circleLayer?.strokeColor = UIColor.red.cgColor
90
+ circleLayer?.strokeColor = UIColor.red.cgColor
77
- circleLayer?.fillColor = UIColor.clear.cgColor
91
+ circleLayer?.fillColor = UIColor.clear.cgColor
78
- circleLayer?.lineWidth = 2.0
92
+ circleLayer?.lineWidth = 2.0
79
- circleLayer?.add(animation, forKey: nil)
93
+ circleLayer?.add(animation, forKey: nil)
80
- chartView.layer.addSublayer(circleLayer!)
94
+ chartView.layer.addSublayer(circleLayer!)
95
+ }
81
96
  }
82
97
  }
83
98
  }
99
+
84
100
  ```

1

試行したコードを追記

2020/09/17 08:53

投稿

TsukubaDepot
TsukubaDepot

スコア5086

answer CHANGED
@@ -40,4 +40,45 @@
40
40
 
41
41
  本当は、アニメーションに対して適切な keyPath を設定し、次回以降はそれを使って削除できれば見通しが良いのですが、なぜかうまくいかなかったので、 ViewController のプロパティとして `CAShapeLayer` のプロパティを持たせ、2回目以降はそれを使ってアニメーションを消すようにしています。
42
42
 
43
- この実装はまだ中途半端で、たとえばスケールファクターを変更した場合には、赤丸が残ったまま追従しないなどの問題もありますが、それは追々解決していただければと思います。
43
+ この実装はまだ中途半端で、たとえばスケールファクターを変更した場合には、赤丸が残ったまま追従しないなどの問題もありますが、それは追々解決していただければと思います。
44
+
45
+ ##指定したポイントに円弧を描くためのコードの書きかけ
46
+ ```Swift
47
+ // 表示が完全に止まったら呼び出される delegate
48
+ func chartView(_ chartView: ChartViewBase, animatorDidStop animator: Animator) {
49
+ print(#function)
50
+ //chartView.highlightValue(Highlight(x: values[19].x, y: values[19].y, dataSetIndex: 0), callDelegate: true)
51
+ if let set1 = chartView.data?.getDataSetByIndex(0) {
52
+ if let val = set1.entryForIndex(19) {
53
+ // ハイライトさせる
54
+ chartView.highlightValue(Highlight(x: val.x, y: val.y, dataSetIndex: 0), callDelegate: true)
55
+
56
+ // ここで得られるハイライト座標には、View 内部での座標(xPx, yPx)が代入されないため、円弧を書くための座標を算出することができない
57
+ let hightlight = Highlight(x: val.x, y: val.y, dataSetIndex: 0)
58
+
59
+ // 点滅させる
60
+ // ** 以下のコードを実施しても、xPx, yPx が nan のため正しく表示されない
61
+ // 以前のアニメーションを消す
62
+ circleLayer?.removeFromSuperlayer()
63
+
64
+ // 透明度のアニメーションを設定する。
65
+ // alpha ではなく、opacity であることに注意。
66
+ let animation = CAKeyframeAnimation(keyPath: "opacity")
67
+ animation.duration = 1
68
+ animation.keyTimes = [0.0, 0.5, 1.0]
69
+ animation.values = [1.0, 0.00, 1.0]
70
+ animation.repeatCount = .greatestFiniteMagnitude
71
+
72
+ // タップされた座標を中心として円形を作る
73
+ circleLayer = CAShapeLayer()
74
+ let circlePath = UIBezierPath(arcCenter: CGPoint(x: highlight.xPx, y: highlight.yPx), radius: 20, startAngle: 0, endAngle: .pi*2, clockwise: true)
75
+ circleLayer?.path = circlePath.cgPath
76
+ circleLayer?.strokeColor = UIColor.red.cgColor
77
+ circleLayer?.fillColor = UIColor.clear.cgColor
78
+ circleLayer?.lineWidth = 2.0
79
+ circleLayer?.add(animation, forKey: nil)
80
+ chartView.layer.addSublayer(circleLayer!)
81
+ }
82
+ }
83
+ }
84
+ ```