绘制K线第一章:可见区间处理

绘制K线第一章:可见区间处理

概述

在入门版本中,我们绘制了所有K线数据。但当数据量很大时,所有K线会挤在一起或超出屏幕,无法正常显示。

可见区间处理就是解决这个问题:只绘制屏幕能容纳的K线数量,让图表清晰可读。

为什么需要可见区间

问题场景

假设有以下情况:

  • 屏幕宽度:1080px
  • 每根K线占用:30px(20px宽度 + 10px间距)
  • 可显示的K线数量:1080 ÷ 30 = 36根
  • 实际数据:1000根K线

如果绘制所有1000根K线:

  • K线会挤在一起,无法看清
  • 或者超出屏幕,看不到完整内容

解决方案

只显示最后36根K线(最新的数据),这样:

  • K线清晰可读
  • 不会超出屏幕

实现原理

核心逻辑

scss 复制代码
// 1. 计算可见K线数量
val totalCandleWidth = config.getTotalCandleWidth()  // 30px
val visibleCount = (width / totalCandleWidth).toInt()  // 1080 ÷ 30 = 36

// 2. 获取可见数据(只取最后N根)
val visibleData = if (klineData.size > visibleCount) {
    klineData.takeLast(visibleCount)  // 取最后36根
} else {
    klineData  // 数据不足,全部显示
}

// 3. 只对可见数据计算价格范围
val priceRange = calculatePriceRange(visibleData)

// 4. 只绘制可见数据
visibleData.forEachIndexed { index, entity ->
    drawCandle(...)
}

关键点

  1. 计算可见数量屏幕宽度 ÷ 每根K线占用宽度
  2. 取最后N根 :使用 takeLast() 方法,显示最新的数据
  3. 价格范围计算:只基于可见数据计算,确保Y轴比例正确

代码实现(KLineViewCase2)

类图

kotlin 复制代码
@startuml
class KLineViewCase2 {
  - klineData: List<KLineEntity>
  - config: KLineConfig
  + setKLineData(data: List<KLineEntity>)
  - calculatePriceRange(data: List<KLineEntity>): Pair<Float, Float>
}

KLineViewCase2 --> KLineConfig : 依赖
KLineViewCase2 --> KLineEntity : 使用

note right of KLineViewCase2
  相比Case1,增加了可见区间处理:
  1. 计算可见K线数量
  2. 只取最后N根数据
  3. 只对可见数据计算价格范围
end note

@enduml

核心代码(可见区间部分)

onDraw() 方法中,相比Case1增加了可见区间处理:

scss 复制代码
// 1. 计算可见区间:根据屏幕宽度计算能显示多少根K线
val totalCandleWidth = config.getTotalCandleWidth()
val visibleCount = (width / totalCandleWidth).toInt()

// 2. 获取可见的K线数据(只显示最后N根,最新的数据)
val visibleData = if (klineData.size > visibleCount) {
    klineData.takeLast(visibleCount)  // 取最后N根
} else {
    klineData  // 数据不足,全部显示
}

// 3. 计算可见数据的价格范围(注意:传入visibleData而不是klineData)
val priceRange = calculatePriceRange(visibleData)

// 4. 绘制可见的K线(使用visibleData)
visibleData.forEachIndexed { index, entity ->
    drawCandle(canvas, entity, index, minPrice, maxPrice, height)
}

关键改动

  • calculatePriceRange() 方法现在接受 data 参数,可以传入可见数据
  • 其他绘制逻辑与Case1相同(参考入门文档)

与Case1的对比

特性 Case1(入门版) Case2(可见区间版)
绘制数据 所有数据 只绘制可见数据(最后N根)
价格范围计算 基于所有数据 基于可见数据
适用场景 数据量小(< 50根) 数据量大(> 50根)
代码复杂度 简单 稍复杂(增加可见区间逻辑)

完整绘制链路

相比Case1,Case2在绘制链路中增加了可见区间处理:

scss 复制代码
1. 设置K线数据 → 触发onDraw()重绘
   ↓
2. onDraw()方法执行:
   ├─ 绘制背景(与Case1相同)
   ├─ 检查数据是否为空(与Case1相同)
   ├─ 【新增】计算可见区间
   │   ├─ 计算可见K线数量(屏幕宽度 ÷ 每根K线宽度)
   │   └─ 获取可见数据(取最后N根)
   ├─ 计算价格范围(基于可见数据,不是所有数据)
   └─ 遍历可见K线数据并绘制(绘制逻辑与Case1相同)

说明:绘制K线的具体步骤(计算坐标、绘制影线、绘制实体)与Case1相同,参考入门文档。

关键概念

可见K线数量计算

scss 复制代码
可显示的K线数量 = 屏幕宽度 ÷ 每根K线占用的总宽度
                = width ÷ (candleWidth + candleSpacing)
                = width ÷ totalCandleWidth

示例

  • 屏幕宽度:1080px
  • 每根K线占用:30px(20px宽度 + 10px间距)
  • 可见数量:1080 ÷ 30 = 36根

取最后N根数据

arduino 复制代码
val visibleData = if (klineData.size > visibleCount) {
    klineData.takeLast(visibleCount)  // 取最后N根(最新数据)
} else {
    klineData  // 数据不足,全部显示
}

说明

  • 如果数据量 > 可见数量:只取最后N根(显示最新数据)
  • 如果数据量 ≤ 可见数量:全部显示

价格范围只基于可见数据

这是关键点:价格范围必须只基于可见数据计算,而不是所有数据。

为什么?

  • 如果基于所有数据计算价格范围,可见数据的价格变化可能很小
  • 导致Y轴比例不合适,K线看起来像一条线
  • 只基于可见数据计算,Y轴比例正确,K线清晰可见

注意事项

  1. 数据顺序 :确保数据是按时间顺序排列的(从旧到新),这样 takeLast() 才能取到最新数据
  2. 边界情况:当数据量小于可见数量时,需要全部显示
  3. 价格范围:必须只基于可见数据计算,不能基于所有数据

总结

可见区间处理是K线绘制的重要优化:

  • 解决数据量大时的显示问题
  • 只绘制屏幕能容纳的K线
  • 价格范围只基于可见数据计算
  • 为后续的滚动、缩放功能打下基础

效果

相关推荐
roman_日积跬步-终至千里1 小时前
【架构设计与实现】动态数据源切换:核心代码实现手册
java
XiaoFan0121 小时前
免密批量抓取日志并集中输出
java·linux·服务器
顾北121 小时前
MCP服务端开发:图片搜索助力旅游计划
java·spring boot·dubbo
我命由我123451 小时前
Android 广播 - 静态注册与动态注册对广播接收器实例创建的影响
android·java·开发语言·java-ee·android studio·android-studio·android runtime
赛姐在努力.1 小时前
【拓扑排序】-- 算法原理讲解,及实现拓扑排序,附赠热门例题
java·算法·图论
yxc_inspire1 小时前
Java学习第二天
java·面向对象
毕设源码-赖学姐1 小时前
【开题答辩全过程】以 基于net超市销售管理系统为例,包含答辩的问题和答案
java
昀贝2 小时前
IDEA启动SpringBoot项目时报错:命令行过长
java·spring boot·intellij-idea
roman_日积跬步-终至千里2 小时前
【LangGraph4j】LangGraph4j 核心概念与图编排原理
java·服务器·数据库
野犬寒鸦3 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法