记录测试代码
import android.graphics.Color
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.Gravity
import com.blankj.utilcode.util.SizeUtils
import java.util.*
import kotlin.random.Random
class TestChartActivity : BaseActivity() {
private lateinit var binding: ActivityTestBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTestBinding.inflate(layoutInflater)
setContentView(binding.root)
initView()
}
fun initView() {
val functions = arrayListOf(Runnable { testHorizontal() },
Runnable { fillChartTest() },
Runnable { dotLineAndHistogramTest() },
Runnable { multiPointTest() },
Runnable { multiHistogramTest() },
Runnable { dotLineWithHistogramTest() },
Runnable { compareHistogram() },
Runnable { pointTest() },
Runnable { colorsHistogram() },
Runnable { overlapHistogram() },
Runnable { dynamicTrendChart() },
Runnable { splitHisChart() },
Runnable { testTextHorizontal() },
Runnable { testRangeSelector() }
)
val layout = binding.testBtnLayout
for (i in 0 until layout.childCount) {
layout.getChildAt(i).setOnClickListener() {
functions[i].run()
}
}
binding.testTrendChart.setNoDataMessage("暂无数据")
}
fun testHorizontal() {
val axisText = arrayListOf("卖出", "中性", "持有", "推荐", "买入")
binding.testHorizontalChart.run {
getAxisConfig().apply {
xAxisRule = PositiveZeroAxisRule()
xSplitCount = 5
leftAxisRule = FixedTextAxisRule(axisText)
}
getHighlightConfig().highlightPackager = HorizontalSimplePackager()
setShouldAnimated(true)
}
val chartData = HorizontalHisData()
chartData.rowData("", arrayListOf(), doubleArrayOf(0.0, 0.0, 0.0, 12.0, 34.0))
.renderBy(HorizontalHisRenderer(HistogramConfig(Palette.getChartColor(0))))
chartData.yRawData = axisText
binding.testHorizontalChart.setData(arrayListOf(chartData))
}
fun testTextHorizontal() {
val axisText = arrayListOf("卖出", "中性", "持有", "推荐", "买入")
binding.testHorizontalChart.run {
getAxisConfig().apply {
xAxisRule = PositiveZeroAxisRule()
xSplitCount = 5
leftAxisRule = FixedTextAxisRule(axisText)
yAxisTextAlign = Alignment.CENTER
xAxisTextAlign = Flex.CENTER
}
getHighlightConfig().highlightPackager = HorizontalSimplePackager()
setShouldAnimated(true)
}
val chartData = HorizontalHisData()
chartData.rowData("", arrayListOf(), doubleArrayOf(2.0, 5.0, 10.0, 12.0, 34.0))
.renderBy(TextHorizontalHisRenderer(TextHistogramConfig(Palette.getChartColor(0)).apply {
drawFromLeftToRight = true
val origin = textPackager
textPackager = {
origin.invoke(it) + "%"
}
}))
chartData.isLeftData = true
chartData.yRawData = axisText
binding.testHorizontalChart.setData(arrayListOf(chartData))
}
fun testRangeSelector() {
val rangeSelector = binding.testRangeSelector
rangeSelector.registerMaster(binding.testTrendChart,object:OnRangeChangedListener<CoordinateRangeModel>{
override fun onRangeChangeStart(startModel: CoordinateRangeModel) {
LogHelper.i("Range Select","Select start.Start range is: ${startModel.left} to ${startModel.right}")
}
override fun onRangeChanging(latestModel: CoordinateRangeModel) {
LogHelper.i("Range Select","Current range is: ${latestModel.left} to ${latestModel.right}")
}
override fun onRangeChangedEnd(lastModel: CoordinateRangeModel) {
LogHelper.i("Range Select","Select end.Last range is: ${lastModel.left} to ${lastModel.right}")
}
})
}
private fun fillChartTest() {
ChartDataProvider.provideTest2Data {
binding.testTrendChart.setData(listOf(convertData(it)))
}
}
private fun convertData(ori: List<List<String>>): TrendOriginData {
var trendData = TrendOriginData()
val size = ori.size
val yData = DoubleArray(size)
val xRawData = arrayListOf<String>()
val xData = DoubleArray(size)
for (i in 0 until size) {
yData[i] = StringUtils.valueOfDouble(ori[i][2])
xRawData.add(ori[i][0])
xData[i] = CalculateUtil.transformTime(ori[i][0], "yyyy-MM-dd")
}
trendData.rowData("日期", xRawData, xData)
.columnData("收盘价", yData)
.originSign("贵州茅台")
.renderBy(FillTrendRenderer(FillTrendConfig(Palette.getChartColor(0))))
binding.testTrendChart.apply {
getAxisConfig().apply {
xAxisRule = FixedTextAxisRule.getInstanceFromTexts(xRawData, 3)
leftAxisRule = PositiveZeroAxisRule()
xAxisTextAlign = Flex.SPACE_BETWEEN
}
getHighlightConfig().highlightPackager = PolyLinePackager()
getTitleConfig().content = "折线填充图"
}
return trendData
}
private fun dotLineAndHistogramTest() {
ChartDataProvider.provideTest3Data { dates, values, dateStrs, compareValue ->
val trendData: TrendOriginData = HistogramData().apply {
rowData(
"时间", dateStrs,
CalculateUtil.transformTime(dates.asList(), "yyyyMMdd")
)
.columnData("每股收益", values)
.originSign("康尼机电", "每股收益")
.renderBy(HistogramRenderer(HistogramConfig(Palette.getChartColor(0)).apply {
couldLabelClick = true
}))
}
val compareData: TrendOriginData = TrendOriginData().apply {
rowData(
"时间", dateStrs,
CalculateUtil.transformTime(dates.asList(), "yyyyMMdd")
)
.columnData("同比收益", compareValue)
.originSign("康尼机电", "同比")
.renderBy(EvenlyDotLineRenderer(DotLineConfig(Palette.getChartColor(1)).apply {
couldLabelClick = true
}))
isLeftData = false
}
binding.testTrendChart.apply {
getAxisConfig().apply {
leftYSplitCount = 5
rightYSplitCount = 5
leftAxisRule = AroundZeroAxisRule()
rightAxisRule = UnitAxisRule("%", AroundZeroAxisRule())
xAxisTextAlign = Flex.SPACE_BETWEEN
xAxisRule = FixedTextAxisRule.getInstanceFromTexts(dateStrs, 3)
}
getHighlightConfig().highlightPackager = PolyLinePackager()
getTitleConfig().content = "折线&柱状图"
setData(listOf(trendData, compareData))
}
}
}
fun multiPointTest() {
ChartDataProvider.provideTest4Data { xData, yData, multiData, forecastYData ->
val companyForecastData: ColumnMultiData = MultiScatterData()
val totalForecastData = TrendOriginData()
companyForecastData.apply {
originSign("", "EPS")
.columnData(label, forecastYData)
.rowData("日期", xData, CalculateUtil.transformTime(xData))
.renderBy(ColumnMultiPointRenderer(DotLineConfig(Palette.getChartColor(1)).apply {
shouldDrawMarkOnHighlight = false
dotRadius = SizeUtils.dp2px(3f).toFloat()
couldLabelClick = true
}))
yMultiData = multiData
}
totalForecastData.apply {
originSign("一致预测值", "一致预测值")
.columnData(label, yData)
.rowData("日期", xData, CalculateUtil.transformTime(xData))
.renderBy(PolyLineRenderer(DotLineConfig(Palette.getChartColor(3)).apply {
shouldDrawMarkOnHighlight = false
couldLabelClick = true
}))
}
binding.testTrendChart.apply {
getAxisConfig().apply {
leftYSplitCount = 4
leftAxisRule = FormattedAxisRule()
xAxisRule = FixedTextAxisRule.getInstanceFromTexts(xData, 3)
shouldLeftPadding = true
}
getHighlightConfig().highlightPackager = ComparePackager()
getTitleConfig().content = "纵行多点图"
setData(arrayListOf(companyForecastData, totalForecastData))
}
}
}
fun multiHistogramTest() {
ChartDataProvider.provideTest5Data { model ->
val multiData = ForecastAdjustModel.ForecastMultiData()
val multiDataRecord = arrayListOf<ColumnMultiData.MultiDataPair>()
val xData = arrayListOf<String>()
val yForecastData = arrayListOf<Double>()
for (dayData in model) {
xData.add(dayData[0])
yForecastData.add(StringUtils.valueOfDouble(dayData[1]))
val pairs = arrayListOf<Pair<String, Double>>()
pairs.add(Pair("上调预测", StringUtils.valueOfDouble(dayData[2])))
pairs.add(Pair("维持预测", StringUtils.valueOfDouble(dayData[4])))
pairs.add(Pair("下调预测", StringUtils.valueOfDouble(dayData[3])))
multiDataRecord.add(ColumnMultiData.MultiDataPair(dayData[0], pairs))
}
multiData.apply {
yMultiData = multiDataRecord
this.xRawData = xData
label = "预测"
this.xData = CalculateUtil.transformTime(xData)
renderer = ProportionHistogramRender(ProportionHistogramConfig().apply {
showProportionValue = true
})
xDataName = "时间"
yDataName = label
}
val trendData = TrendOriginData()
trendData.apply {
rowData("时间", xData, CalculateUtil.transformTime(xData))
.columnData("EPS", yForecastData.toDoubleArray(), isLeft = false)
.originSign("EPS")
.renderBy(EvenlyPolyLineRenderer(DotLineConfig(Palette.getChartColor(3))))
}
binding.testTrendChart.apply {
getAxisConfig().apply {
leftYSplitCount = 6
leftAxisRule = UnitAxisRule("%", FixedSplitAxisRule(doubleArrayOf(0.0, 100.0)))
yAxisTextAlign = Alignment.CENTER
rightAxisRule = FormattedAxisRule()
xAxisRule = FixedTextAxisRule.getInstanceFromTexts(xData, 3)
shouldLeftPadding = false
}
getLabelConfig().apply {
labelColumnNum = 4
}
getHighlightConfig().highlightPackager = ComparePackager()
getTitleConfig().content = "纵向叠加柱状图"
getTitleConfig().titleGravity = Gravity.CENTER
getTitleConfig().titleLocation = Location.TOP
setData(arrayListOf(multiData, trendData))
}
}
}
fun dotLineWithHistogramTest() {
ChartDataProvider.provideTest6Data { upValues, downValues, yValues ->
val dateNames =
arrayOf("最新新新新新新", "1月前前前前前前", "2月前前前前前前", "3月前前前前前前", "4月前", "5月前", "6月前")
val histogramConfig = HistogramConfig(Palette.getChartColor(2)).apply {
shouldShowOnHighlight = false
fixedWidth = SizeUtils.dp2px(5f).toFloat()
}
val chartData = HistogramData().apply {
rowData("", dateNames.asList())
columnData("", upValues.toDoubleArray())
renderBy(HistogramRenderer(histogramConfig))
startPoints = downValues
}
val dotLineData = TrendOriginData().apply {
rowData("", dateNames.asList())
.columnData("", yValues.toDoubleArray())
.originSign("一致目标价", "")
.renderBy(
EvenlyDotLineRenderer(
DotLineConfig(Palette.getChartColor(1))
.apply {
shouldDrawMarkOnHighlight = false
line(Color.parseColor("#FF404043"))
point(radius = SizeUtils.dp2px(3f).toFloat())
})
)
}
binding.testTrendChart.apply {
setAxisRender(AdaptiveAxisRenderer(AdaptiveAxisConfig()))
getAxisConfig().apply {
leftAxisRule = EvenSplitAxisRule(0.5f)
xAxisTextAlign = Flex.SPACE_AROUND
xAxisRule = FixedTextAxisRule(dateNames.asList())
if (this is AdaptiveAxisConfig) {
drawXAxisInclined = true
drawXAxisEllipsis = false
}
}
getHighlightConfig().highlightPackager = SimplePackager()
getTitleConfig().content = "带量柱的点线图"
setData(arrayListOf(chartData, dotLineData))
}
}
}
fun compareHistogram() {
val stockList = doubleArrayOf(92.35, 92.57)
val bondList = doubleArrayOf(0.37, 0.0)
val fundList = doubleArrayOf(0.0, 0.0)
val cashList = doubleArrayOf(5.27, 8.36)
val otherList = doubleArrayOf(2.76, 1.31)
val nameList = arrayListOf("张坤", "蔡嵩松")
val multiData = arrayListOf<ColumnMultiData.MultiDataPair>()
for (i in 0..1) {
val pairs = arrayListOf<Pair<String, Double>>()
pairs.add(Pair("股票", stockList[i]))
pairs.add(Pair("债券", bondList[i]))
pairs.add(Pair("基金", fundList[i]))
pairs.add(Pair("现金", cashList[i]))
pairs.add(Pair("其他", otherList[i]))
multiData.add(ColumnMultiData.MultiDataPair(nameList[i], pairs))
}
val chartData = MultiProportionData().apply {
rowData("", nameList)
yMultiData = multiData
renderBy(ProportionHistogramRender(ProportionHistogramConfig().apply {
quantifyUpperLimit = 100f
}))
}
binding.testTrendChart.apply {
getAxisConfig().apply {
leftYSplitCount = 5
unitList = arrayListOf("%")
unitMargin = SizeUtils.dp2px(16f).toFloat()
leftAxisRule = FixedSplitAxisRule(doubleArrayOf(0.0, 125.0))
leftYSplitCount = 6
xAxisRule = FixedTextAxisRule(nameList)
xAxisTextAlign = Flex.SPACE_AROUND
}
getHighlightConfig().highlightPackager = ComparePackager()
getLabelConfig().labelColumnNum = 3
getTitleConfig().content = "比较纵向叠加柱状图"
setData(arrayListOf(chartData))
}
}
fun pointTest() {
val chartData = TrendOriginData()
val xData = DoubleArray(15) { Random(it).nextDouble() }
val xRawData = Array<String>(xData.size) { NumberFormatUtil.formatNum(xData[it], 1) }
chartData.rowData("随机数值", xRawData.asList(), xData)
.columnData("随机值", xData, true)
.originSign("随机")
.renderBy(ScatterRenderer(DotLineConfig(Palette.getChartColor(4)).apply {
shouldDrawMarkOnHighlight = false
couldLabelClick = false
}))
binding.testTrendChart.apply {
getAxisConfig().apply {
xAxisRule = EvenSplitAxisRule(1f)
xAxisTextAlign = Flex.CENTER
shouldLeftPadding = true
xSplitCount = 3
leftAxisRule = FormattedAxisRule()
leftYSplitCount = 6
}
getTitleConfig().content = "散点图"
setData(arrayListOf(chartData))
}
}
fun colorsHistogram() {
val chartData = HistogramData().apply {
rowData("时间", getQuantifyData(15).map { it.toString() }, getQuantifyData(15))
.columnData("资金", DoubleArray(15) {
(it * 10 + Random(System.currentTimeMillis()).nextInt(-100, 50)).toDouble()
})
.renderBy(ColorsHistogramRenderer(ColorsHistogramConfig()))
}
binding.testTrendChart.apply {
setAxisRender(SingleLineAxisRenderer(AxisConfig().apply {
shouldLeftPadding = true
}))
getTitleConfig().content = "多色柱状图"
setData(arrayListOf(chartData))
}
}
fun overlapHistogram() {
val originData = doubleArrayOf(21000.0, -18000.0, 6000.0, -1000.0, 15000.0, -8000.0)
val chartData = object : HistogramData() {
override fun getLabelData(): List<LabelData> {
return ArrayList<LabelData>(originData.size).apply {
for (i in 0 until originData.size) {
add(LabelData(i.toString(), Palette.getChartColor(i), true))
}
}
}
}.rowData(
"",
Array<String>(originData.size) { "" }.toList(),
DoubleArray(originData.size, { (it / 2).toDouble() })
)
.columnData("", originData).apply {
renderBy(ShareholdersHistogramRenderer(ColorsHistogramConfig()))
}
binding.testTrendChart.apply {
setAxisRender(ExtraAxisRenderer(ExtraAxisConfig().apply {
leftAxisRule = AroundZeroAxisRule()
extraLineColor = Color.WHITE
yAxisTextAlign = Alignment.CENTER
}))
getLabelConfig().location = Location.TOP
getTitleConfig().titleLocation = Location.BOTTOM
setData(arrayListOf(chartData))
}
}
fun dynamicTrendChart() {
ChartDataProvider.provideTest2Data { ori ->
val trendData = TrendOriginData()
val dynamicData: DynamicChartData = DynamicTrendOriginData(trendData)
val size = ori.size / 2
val yData = DoubleArray(size)
val xRawData = arrayListOf<String>()
val xData = DoubleArray(size)
val yRemainData = DoubleArray(size)
val xRemainRawData = arrayListOf<String>()
val xRemainData = DoubleArray(size)
for (i in 0 until size * 2) {
if (i < size) {
yData[i] = StringUtils.valueOfDouble(ori[i][2])
xRawData.add(ori[i][0])
xData[i] = CalculateUtil.transformTime(ori[i][0], "yyyy-MM-dd")
} else {
yRemainData[i - size] = StringUtils.valueOfDouble(ori[i][2])
xRemainRawData.add(ori[i][0])
xRemainData[i - size] = CalculateUtil.transformTime(ori[i][0], "yyyy-MM-dd")
}
}
DynamicDataHandler.yRemainData = yRemainData
DynamicDataHandler.xRemainData = xRemainData
DynamicDataHandler.xRemainRawData = xRemainRawData
val actualRenderer = DynamicPolyLineRenderer(PolyLineConfig(Palette.getChartColor(0)))
trendData.rowData("日期", xRawData, xData)
.columnData("收盘价", yData)
.originSign("贵州茅台")
trendData.renderBy(actualRenderer)
trendData.isLeftData = false
val compareData = TrendOriginData().rowData("日期", xRawData, xData)
.columnData("拟合线", yData.map { it + 500 }.toDoubleArray())
.originSign("拟合线")
.apply {
renderBy(PolyLineRenderer(PolyLineConfig(Palette.getChartColor(1))))
}
binding.testDynamicTrendChart.apply {
getAxisConfig().apply {
xAxisRule = FixedResultAxisRule(
doubleArrayOf(xData.first(), xRemainData.last()),
arrayListOf(xRawData.first(), xRawData.last(), xRemainRawData.last())
)
leftAxisRule = PositiveZeroAxisRule()
rightAxisRule = PositiveZeroAxisRule()
xAxisTextAlign = Flex.SPACE_BETWEEN
}
getHighlightConfig().highlightPackager = PolyLinePackager()
getTitleConfig().content = "动态数据趋势图"
setData(listOf(compareData, dynamicData))
}
dynamicAddData()
}
}
fun splitHisChart() {
val firstChartData = HistogramData().apply {
rowData("时间", getQuantifyData(15).map { it.toString() }, getQuantifyData(15))
.columnData("资金", DoubleArray(15) {
(it * 10 + Random(System.currentTimeMillis()).nextInt(-100, 50)).toDouble()
})
.originSign("时间")
.renderBy(SplitHistogramRenderer(SplitHistogramConfig(Palette.getChartColor(0)).apply {
splitCount = 2
splitIndex = 1
}))
}
val secondChartData = HistogramData().apply {
rowData("空间", getQuantifyData(15).map { it.toString() }, getQuantifyData(15))
.columnData("资金", DoubleArray(15) {
(it * 10 + Random(System.currentTimeMillis()).nextInt(-100, 50)).toDouble()
})
.originSign("空间")
.renderBy(SplitHistogramRenderer(SplitHistogramConfig(Palette.getChartColor(1)).apply {
splitCount = 2
splitIndex = 2
}))
}
binding.testTrendChart.apply {
getAxisConfig().apply {
leftAxisRule = AroundZeroAxisRule()
xAxisRule = EvenSplitAxisRule(1f)
}
getHighlightConfig().highlightPackager = ComparePackager()
getTitleConfig().content = "并排分割柱状图"
setData(arrayListOf(firstChartData, secondChartData))
}
}
fun dynamicAddData() {
object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
dynamicUpdateRunnable.run()
if (DynamicDataHandler.index < DynamicDataHandler.xRemainData.size - 1) {
DynamicDataHandler.index++
sendEmptyMessageDelayed(1, 50)
} else {
DynamicDataHandler.index = 0
}
}
}.sendEmptyMessageDelayed(1, 2000)
}
object DynamicDataHandler {
var index = 0
var yRemainData = doubleArrayOf()
var xRemainRawData = arrayListOf<String>()
var xRemainData = doubleArrayOf()
}
val dynamicUpdateRunnable = Runnable {
val item = ChartDataItem()
item.xRawItem = DynamicDataHandler.xRemainRawData[DynamicDataHandler.index]
item.yValueItem = DynamicDataHandler.yRemainData[DynamicDataHandler.index]
item.xValueItem = DynamicDataHandler.xRemainData[DynamicDataHandler.index]
binding.testDynamicTrendChart.apply {
appendItem(1, item)
}
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<FrameLayout
android:id="@+id/test_chart_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ui.chart.charts.TrendChart
android:id="@+id/test_trend_chart"
android:layout_width="match_parent"
android:layout_height="260dp"
android:layout_gravity="center_vertical" />
<ui.chart.charts.DynamicTrendChart
android:id="@+id/test_dynamic_trend_chart"
android:layout_width="match_parent"
android:layout_height="260dp"
android:layout_gravity="center_vertical" />
<ui.chart.charts.HorizontalHisChart
android:id="@+id/test_horizontal_chart"
android:layout_width="match_parent"
android:layout_height="260dp"
android:layout_gravity="center_vertical" />
</LinearLayout>
<ui.rangeselector.widget.CoordinateRangeSelector
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/test_range_selector"/>
</FrameLayout>
</ScrollView>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ui.FlowLayout
android:id="@+id/test_btn_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="24dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="横向柱状图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="折线填充图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="折线柱状图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="纵行多点图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="纵向叠加柱状图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="带量柱的点线图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="比较纵向叠加柱状图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="散点图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="多色矩形图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="重叠柱状图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="动态添加数据折线图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="并排分割柱状图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="带文字的横向柱状图" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="范围选择器" />
</ui.FlowLayout>
</ScrollView>
</LinearLayout>
UI图