アプリ開発#2「vehcle G simulator vol1」

アプリ開発

android app.です。
こちらはkotlinで開発しました。
物理モデルはこちら

アプリ紹介

該当アプリはこちらになります。

Google Play で手に入れよう

紹介動画

苦労した点

ここでは主にMPandroidchartで苦労したことをまとめる。

combined viewにてline chart, scatter plot を作成

当該アクティビティに記載

//combinedchart用の設定
private fun setupCombinedChart() {
 combinedChart.apply {
  description.isEnabled = false
  setTouchEnabled(true)
  isDragEnabled = true
  isScaleXEnabled = true
  setPinchZoom(false)
  setDrawGridBackground(false)
//y軸右側の表示
  axisRight.isEnabled = false
//X軸表示
  xAxis.apply {
  typeface = mTypeface
  setDrawGridLines(true)
  textColor = Color.BLACK
  axisMinimum = 0f
  axisMaximum = 3f
  labelCount = 3
  }
//y軸左側の表示
  axisLeft.apply {
  typeface = mTypeface
  textColor = Color.BLACK
  setDrawGridLines(true)
  axisMinimum = -50f
  axisMaximum = 150f
  labelCount = 4
  }
 }
}

// LineChartデータ作成
private fun setupLineChart(Te_time_:List<Entry>): LineData {
 var values2=Te_time_
 val yVals2 = LineDataSet(values2, "Te [Nm]").apply {
  axisDependency = YAxis.AxisDependency.LEFT
  color = Color.BLACK
  highLightColor = Color.BLUE
  setDrawCircles(true)
  setDrawCircleHole(false)
  setDrawValues(false)
  lineWidth = 2f
 }
 val data=LineData(yVals2)
 data.setValueTextColor(Color.BLACK)
 data.setValueTextSize(9f)
 return data
}

// scatterChartデータ作成
private fun setupscatterChart(Temp00_:List<Entry>): ScatterData {
 var values1=Temp00_
 val yVals1 = ScatterDataSet(values1, "").apply {
  axisDependency = YAxis.AxisDependency.LEFT
  //透明色
  color = Color.TRANSPARENT
  highLightColor = Color.TRANSPARENT
  setDrawValues(false)
 }
 val data=ScatterData(yVals1)
 data.setValueTextColor(Color.BLACK)
 data.setValueTextSize(9f)
 return data
}

レイアウトファイルには以下を記載

<com.github.mikephil.charting.charts.CombinedChart
android:id="@+id/combinedChart"
android:layout_width="match_parent"
android:layout_height="350dp" />

事前にscatter plotでグラフ全体に透明色でプロット

透明色は前の工程で設定済

for (k in 1..30){
 for (l in 1..2000){
  Temp00.add(Entry(k/10f,l/10f-50f))
 }
}

setupCombinedChart()
val combinedData=CombinedData()
combinedData.setData(setupscatterChart(Temp00))
combinedData.setData(setupLineChart(Te_time))
combinedChart.data=combinedData

タッチしたときにscatter plotの値を拾い、line chartに代入

これでタッチしたときの値を拾う

class CustomMarkerView(context: Context?, layoutResource: Int) :MarkerView(context, layoutResource) {
 private val tvContent: TextView
 override fun refreshContent(
  e: Entry,
  highlight: Highlight?
  ) {
   super.refreshContent(e, highlight);
 }

 fun getXOffset(xpos: Float): Int {
 return -(width / 2)
 }

 fun getYOffset(ypos: Float): Int {
 return height
 }

 init {
 tvContent = findViewById<View>(R.id.highlight_V) as TextView
 }
}

highlight_Vの定義は以下のとおり。別途xmlを作成する。

<TextView
android:id="@+id/highlight_V"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="7"
android:textSize="12dp"
android:textColor="@android:color/holo_red_light"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall" />

タッチ後の値を拾ってグラフにプロットする

val customMarkerView =CustomMarkerView(this,R.layout.high_light_value)
combinedChart.setMarkerView(customMarkerView)

combinedChart.setOnChartValueSelectedListener(object : OnChartValueSelectedListener {
 override fun onValueSelected(
  e: Entry,
  h: Highlight
 ){
    if(e.x>temp01){
    time_of_torque1.add(e.x)
    torque_of_time1.add(e.y)
    Te_time.add(Entry(e.x, e.y))
    combinedData.setData(setupLineChart(Te_time))
    combinedChart.data=combinedData
    combinedChart.setMarkerView(customMarkerView)
    temp01=e.x
 }
}
override fun onNothingSelected() {}
})

2軸の設定

linechartの引数を2つ取れるようにする。

setupLineChart()
chart_StaticLineGraph1.data = lineDataWithCount1(Te_time,ratio_time)

グラフの設定。y軸右側が活きるようにする。

private fun setupLineChart() {
 chart_StaticLineGraph1.apply {
  description.isEnabled = false
  setTouchEnabled(true)
  isDragEnabled = false
  isScaleXEnabled = true
  setPinchZoom(true)
  setDrawGridBackground(false)
//y軸右側の表示 ここ!
  axisRight.isEnabled = true
//X軸表示
  xAxis.apply {
   typeface = mTypeface
   setDrawGridLines(true)
   textColor = Color.BLACK
   axisMinimum = 0f
   axisMaximum = 3f
   labelCount = 3
  }
//y軸左側の表示
  axisLeft.apply {
   typeface = mTypeface
   textColor = Color.BLACK
   setDrawGridLines(true)
   axisMinimum = -50f
   axisMaximum = 150f
   labelCount = 4
  }
//y軸右側の表示
  axisRight.apply {
   typeface = mTypeface
   textColor = Color.BLACK
   setDrawGridLines(true)
   axisMinimum = 0f
   axisMaximum = 4f
   labelCount = 4
  }
}

受け取る2つのデータの処理内容をまとめる。

/ LineChart用のデータ作成
private fun lineDataWithCount1(Te_time_:List<Entry>,ratio_:List<Entry>): LineData {
 var values1=Te_time_
 var values2=ratio_

 val yVals1 = LineDataSet(values1, "Torque [Nm]").apply {
 axisDependency = YAxis.AxisDependency.LEFT
 color = Color.BLACK
 highLightColor = Color.YELLOW
 setDrawCircles(false)
 setDrawCircleHole(false)
 setDrawValues(false)
 lineWidth = 2f
 }

 val yVals2 = LineDataSet(values2, "ratio [-]").apply {
  axisDependency = YAxis.AxisDependency.RIGHT
  color = Color.BLUE
  highLightColor = Color.YELLOW
  setDrawCircles(false)
  setDrawCircleHole(false)
  setDrawValues(false)
  lineWidth = 2f
 }

 val dataSets: ArrayList<ILineDataSet> = ArrayList()
 dataSets.add(yVals1)
 dataSets.add(yVals2)
 val data=LineData(dataSets)
 data.setValueTextColor(Color.BLACK)
 data.setValueTextSize(9f)
 return data
}

まとめ

ここでは主にMPandroidchartの使い方を紹介。英語のマニュアルがweb上にあるので、そちらを参考にされると解決につながることがある。