API级别:9
参考官网文档:
使用画布绘制自定义图形(Canvas)-显示图形-基于ArkTS的声明式开发范式-UI开发-开发 | 华为开发者联盟 (huawei.com)
代码:
K线绘制代码
import { KLineBean } from '../bean/KLineBean'
@Component
export struct KLineView{
// 开启抗锯齿
private settings : RenderingContextSettings = new RenderingContextSettings(true)
private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
kLineList: KLineBean[] = new Array()
@State totalWidth:number = 300.0
@State totalHeight:number = 100.0
kLineNum = 30
linePadding = 0.2
lineWidth = 0.2
uH = 0.0
uW = 0.0
aboutToAppear(){
// 初始化数据
for(let i = 0; i < this.kLineNum; i++){
let kLineBean = new KLineBean()
kLineBean.low = Math.floor(Math.random() * 100)
kLineBean.high = kLineBean.low + 30
kLineBean.open = kLineBean.low + Math.floor(Math.random() * 30)
kLineBean.close = kLineBean.low + Math.floor(Math.random() * 30)
this.kLineList.push(kLineBean)
}
this.uH = this.calculatorUnitH(this.kLineList)
this.uW = (this.totalWidth - 20) / this.kLineNum - this.linePadding * 2
}
calculatorUnitH(kLineList: KLineBean[]): number{
let result = 0.0
let lowNum = Number.MAX_VALUE
let highNum = 0.0
for(let i =0; i <kLineList.length; i++){
let bean = kLineList[i]
if(lowNum > bean.low){
lowNum = bean.low
}
if(highNum < bean.high){
highNum = bean.high
}
}
result = (this.totalHeight)/(highNum - lowNum)
return result
}
/**
* 1.设置控件宽高
* 2.根据控件高度的最大和最小值之差,得到绘图的单位长度 unitH = 差/ (高度 - padding)
* 3.根据k线数据数量,得到单位K线的宽度 unitW = w/number
* 4.绘制每根K线的高低线和开盘收盘矩形,并根据开盘收盘价来设置绘制颜色
*/
build(){
Flex(){
Canvas(this.canvasContext).width("100%").height("100%").backgroundColor('#ffffff').onReady(()=>{
this.canvasContext.strokeStyle = '#EDEEEF'
this.canvasContext.strokeRect(0, 0, this.totalWidth, this.totalWidth)
for(let i = 0; i < this.kLineList.length; i++){
let bean = this.kLineList[i]
console.log(" testTag low:" + bean.low + " high:" + bean.high + " open:" + bean.open + " close:" + bean.close)
/// 画线 1.定位线的起点和终点 起点纵轴为 控件高度 - (uH * high), 终点为 控件高度 - (uH * low)
/// 起点横轴为 i * uW + uW/2 + linePadding
// 设置直线的颜色
if(bean.close > bean.open){
this.canvasContext.strokeStyle = '#ff0000'
}else{
this.canvasContext.strokeStyle = '#00ff00'
}
this.canvasContext.lineWidth = this.lineWidth
this.canvasContext.beginPath()
this.canvasContext.moveTo( i * this.uW + this.uW / 2 + (2 * i + 1) * this.linePadding ,this.totalHeight - (this.uH * bean.high))
this.canvasContext.lineTo( i * this.uW + this.uW / 2 + (2 * i + 1) * this.linePadding ,this.totalHeight - (this.uH * bean.low))
this.canvasContext.stroke()
/// 画矩形: 纵轴为 控件高度 - (uH * Math.max(open, close)) 横轴为 i * (uW + linePadding * 2)
/// 宽为 uW,高为 (uH * Math.abs(open - close)
if(bean.close > bean.open){
this.canvasContext.fillStyle = '#ff0000'
}else{
this.canvasContext.fillStyle = '#00ff00'
}
let y = this.totalHeight - (this.uH * Math.max(bean.open, bean.close))
let x = i * (this.uW + this.linePadding * 2) + this.linePadding
let w = this.uW
let h = this.uH * Math.abs(bean.close - bean.open)
if(h == 0){
h = 1;
}
this.canvasContext.fillRect(x,y, w,h)
}
})
}.width('100%').height('100%').padding({left:20})
}
positionXStart(index: number): number{
return index * (this.uW + this.linePadding * 2)
}
positionXCenter(index: number):number{
return index * this.uW + this.uW / 2 + (2 * index + 1) * this.linePadding
}
}
数据结构代码:
export class KLineBean{
low: number
high: number
open: number
close: number
date : string
}
应用效果: