使用canvas实现腾讯自选股K线图

news2024/9/24 1:24:38

前言

平常为了方便看行情就会打开小程序看走势,作为一个开发在看腾讯自选股的日K时就会在想这个玩意是怎么弄的呢?下面我就用h5来实现一个最简K线图。

K线的构成以及画法

  • K线又称阴阳线、棒线、红黑线或蜡烛线。
  • K线是一条柱状的线条,由实体和影线两部分构成。影线在实体上方的部分叫上影线,下方的部分叫下影线。实体分阳线和阴线。其中影线表明当天交易的最高和最低价,而实体表明当天的开盘价和收盘价。 如果收盘价高于开盘价,K线就用红色或者空心显示,称为阳线;反之,收盘价低于开盘价,K线用绿色或实心显示,称为阴线。

了解K线的构成对我们进行绘制有很大的帮助。

效果对比

左边的是我们实现的,右边的是腾讯自选股的。

绘制过程

  • 绘制网格
  • 获取数据、处理数据
  • 绘制K线实体、影线
  • 绘制MA5、10、20日均线
  • 绘制成交量

绘制网格

canvas的宽高由父级定义然后进行动态设置。这样做的好处是外层宽高变了,canvas自动适应。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<style> .dayLine {width: 353px;height: 293px;margin: 30px auto;} </style>
<body><div class="dayLine"><canvas id="canvas"></canvas></div><script src="./tools/dayLine.js"></script><script> const parent = document.getElementsByClassName('dayLine')[0];new dayLine({canvas: document.getElementById('canvas'),height: parent.clientHeight,width: parent.clientWidth}) </script>
</body>
</html> 
字段意思
topHight日K区域
space日K成交量分隔界
botHight成交量区域
;(function(){function dayLine(options) {const { canvas, height, width } = options;canvas.width = width;canvas.height = height;this.canvas = canvas;this.ctx = canvas.getContext('2d');this.topHight = 202;// 顶部日k区域this.space = 20;// 中间空隙this.botHight = 71; // 底部成交量this.init();}dayLine.prototype.init = function() {// 绘制分时网格
	this.mineLine(4);// 绘制成交量网格
	this.dealLine(2);// 绘制网格竖线
	this.verticalLine(3);}dayLine.prototype.mineLine = function(num) {const { ctx, topHight, canvas: { width } } = this;this.topScale = topHight / num;ctx.save();ctx.lineWidth = 1;ctx.translate(0.5, 0.5);ctx.strokeStyle = '#F4F5F6';for(let i = 1; i <= num; i++) {this.drawLine(0, i * this.topScale, width, i * this.topScale);}this.drawLine(0, 1, width, 1);ctx.restore();}window.dayLine = dayLine;
})() 

获取数据、处理数据

数据我们从mock.js生成,地址为https://mock.mengxuegu.com/mock/62f719a8f2652f239bd0a7d1/ds/dayLinex

fetch('https://mock.mengxuegu.com/mock/62f719a8f2652f239bd0a7d1/ds/dayLinex').then( res => {return res.json();
}).then( res => {const parent = document.getElementsByClassName('dayLine')[0];const { data } = res;new dayLine({canvas: document.getElementById('canvas'),height: parent.clientHeight,width: parent.clientWidth,data: data})
}) 

获取完数据后将数据传入插件中。

绘制K线实体、影线

了解这几个点,就解除了K线的难点

  • 先确定实体以及影线的颜色只需要记住收盘 < 开盘 = 绿色反过来就是红色
  • 根据开盘、收盘、最高、最低来确定实体以及影线的高度* K线实体高度计算* 柱子是从上到下绘下去的,那么要做的是先确定到底是开盘在上还是收盘在上?* 情况一:收盘 < 开盘柱体是绿色的,那么开盘就是实体的最高点* 情况一:收盘 > 开盘柱体是红色的,那么收盘就是实体的最高点* 如果是绿柱那么开盘在上如果是红柱那么收盘在上* 那么怎么计算柱体高度呢?我这里的话是用开盘的位置 - 收盘的位置得出来的差就是柱体高度,需要转换成绝对值。* 影线的高度计算逻辑同上,唯一不同的是影线是根据最高点以及最低点进行计算的,把上面的开盘、收盘换成最低、最高即可。

那么现在知道了:

  • x轴的刻度
  • y轴的刻度
  • 柱体颜色
  • 柱体长度以及影线长度

看到这里你就已经接近成功了。这里我说下我的数据格式[33,56,89]是这种格式的,因为在实际的业务当中数据量很大,如果都用字段标出来的话会浪费带宽。

下标意思
1开盘
2收盘
3最低
4最高
5成交量
6MA5
7MA10
8MA20
dayLine.prototype.drawDayRect = function() {const { ctx, data: { list }, xScale, topHight, fontSize, maxVal, minVal } = this;const yScale = this.markY({height: topHight,maxVal,minVal})for(let i = 0; i < list.length; i++) {let barX = i * xScale,		// 柱状x坐标barY = 0,				// 柱状y坐标barW = (xScale - 0.8),// 柱状宽度lineY = 0,				// 影线y坐标collect = 0,			// 存储计算柱状高度数据barH = 0,				// 柱状高度lineH = 0;				// 影线高度// 收盘 < 开盘 = 绿色if (list[i][2] < list[i][1]) {// 如果当天是跌的则从开盘开始往下绘制barY = (maxVal - list[i][1]) * yScale;collect = (maxVal - list[i][2]) * yScale;} else {// 如果当天是涨的则从收盘开始往下绘制barY = (maxVal - list[i][2]) * yScale;collect = (maxVal - list[i][1]) * yScale;}// 计算影线长度lineY = (maxVal - list[i][4]) * yScale;lineH = Math.abs(lineY - (maxVal - list[i][3]) * yScale);// 如果柱体小于1 则默认为1不然会绘制不出柱体barH = Math.abs(barY - collect) < 0.5 ? 1 : Math.abs(barY - collect);ctx.beginPath();ctx.fillStyle = list[i][2] < list[i][1] ? '#02BD85' : '#FE5269';// 开盘 - 收盘的绝对值就是柱体高度ctx.rect(barX, barY, barW, barH);// 绘制影线ctx.rect((barX - 0.8) + (barW / 2) + 0.25, lineY, 1, lineH);ctx.fill();}
} 

上面的x轴刻度减0.8是因为要在柱体之间留点空隙,避免粘在一起。

假设我画的canvas宽度是375px,那么刚好iphone6的宽度也是375px,ok那此时是不会模糊的因为没有被拉伸。但是当另一个设备的宽度是400px画布就会被拉伸,拉伸则必然会模糊。

解决方法

我这里的解决方法是:

  • 根据屏幕分辨率将画布放大。假设分辨率是2则375*2=750,画布是750的宽
  • 但实际上我的绘制区域仍然是375,我只需要将我的375直接放大到750那不就成变清晰了吗。
  • ctx.scale(2,2)2替换成分辨率即可。
  • 然后刚才我们上面的利用宽度计算的刻度也得进行修改。
dayLine.prototype.mineLine = function(num) {// 之前是canvas: { width }乘以分辨率后它的值是750,在用这个计算就会超出画布// 所以现在换成传进来的widtdconst { ctx, topHight, width } = this;this.topScale = topHight / num;ctx.save();ctx.lineWidth = 1;ctx.translate(0.5, 0.5);ctx.strokeStyle = '#F4F5F6';for(let i = 1; i <= num; i++) {this.drawLine(0, i * this.topScale, width, i * this.topScale);}this.drawLine(0, 1, width, 1);ctx.restore();
} 

对比上下两张K线图一下就能看出清晰度的区别。

绘制MA5、10、20日均线

什么是均线?

对过去某个时间段的收盘价进行普通平均。比如20日均线,是将过去20个交易日的收盘价相加然后除以20,就得到一个值;再以昨日向前倒推20个交易日,同样的方法计算出另外一个值,以此类推,5日均线,10日均线也由此得来,将这些值连接起来,就形成一个普通均线。

不知道腾讯自选股的均线颜色,我就随便用了三种。均线就是折线。具体画法参考手动实现Antv F2的折线图

绘制成交量

  • 成交量的实现和k线实体差不多,但是更简单。
  • 颜色的话还是收盘 < 开盘 = 绿色反过来就是红色。
  • 柱体高度的话直接值 * 刻度就能拿到。
dayLine.prototype.drawTurnover = function() {const { data: { list }, ctx, xScale, botHight, tMaxVal, tMinVal, topHight, space, width } = this;let maxTurnover = [];let yScale = this.markY({height: botHight,maxVal: tMaxVal,minVal: tMinVal});ctx.save();ctx.lineWidth = 1;for(let i = 0; i < list.length; i++) {let x = i * xScale,y = (topHight + space) + (tMaxVal - list[i][5]) * yScale,w = (xScale - 0.8);maxTurnover.push(list[i][14].replace(/万/,''));ctx.fillStyle = list[i][2] < list[i][1] ? '#02BD85' : '#FE5269';ctx.beginPath();ctx.rect(x, y, w, list[i][5] * yScale);ctx.fill();}const text = `${Math.max(...maxTurnover)}万`;ctx.fillStyle = "#909399";ctx.fillText(text, width - ctx.measureText(text).width - 4, topHight + space + 14);ctx.restore();
} 

总结

我这个只是比较简单的一个K线,里面还有很多细节、功能没有实现。例如十字架、拖动分页等。我大概总结下:

  • 画K线之前得先了解下规律、规则才方便画出来。
  • 如果画出来的图太模糊,就把画布放大。
  • 只要刻度算的准确,难题就差不多都解决了。

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/355347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[数据结构]---八大经典排序算法详解

&#x1f427;作者主页&#xff1a;king&南星 &#x1f3f0;专栏链接&#xff1a;c 文章目录一、八大排序算法复杂度对比二、基于比较的排序算法1.冒泡排序2.选择排序3.插入排序4.希尔排序5.直观感受四种算法的时间复杂度三、基于非比较的排序算法1.基数排序2.箱(桶)排序四…

MySQL 实战记录篇

记录一下在MySQL实战中简单的笔记 MySQL的逻辑架构&#xff0c;一条查询语句是怎么执行的&#xff1f; MySQL 的架构共分为两层&#xff1a;Server 层和存储引擎层 简单的架构图&#xff1a; 连接器&#xff1a;用来和mysql服务器建立连接&#xff0c;tcp三次握手&#xff0…

SpringCloud系列(十三)[分布式搜索引擎篇] - ElasticSearch 的概念及 Centos 7 下详细安装步骤

打开淘宝, 搜索 狂飙 会出现各种价格有关狂飙的书籍, 当然也有高启强同款的孙子兵法!!! 如下图所示: 那么面对海量的数据, 如何快速且准确的找到我们想要的内容呢? 淘宝界面已经可以按照综合排序 / 销量 / 信用 / 价格等进行筛选, 是如何做到的呢? ElasticSearch 11 Elastic…

实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?

上一节课,我们做了一些理论知识的铺垫性讲解,讲到了两种开发模式,基于贫血模型的传统开发模式,以及基于充血模型的DDD开发模式。今天&#xff0c;我们正式进入实战环节&#xff0c;看如何分别用这两种开发模式&#xff0c;设计实现一个钱包系统。话不多说&#xff0c;让我们正式…

python自制PDF转换.PNG格式图片(按每页生成图片完整源码)小工具!

使用PyQt5应用程序制作PDF转换成图片的小工具&#xff0c;可以导入PDF文档后一键生成对应的PNG图片。 PDF图片转换小工具使用的中间件&#xff1a; python版本&#xff1a;3.6.8 UI应用版本&#xff1a;PyQt5 PDF文件操作非标准库&#xff1a;PyPDF2 PNG图片生成库&#xff1…

VINS-Mono/Fusion与OpenCV去畸变对比

VINS中没有直接使用opencv的去畸变函数&#xff0c;而是自己编写了迭代函数完成去畸变操作&#xff0c;主要是为了加快去畸变计算速度 本文对二者的结果精度和耗时进行了对比 VINS-Mono/Fusion与OpenCV去畸变对比1 去畸变原理2 代码实现2.1 OpenCV去畸变2.2 VINS去畸变3 二者对…

压缩20M文件从30秒到1秒的优化过程

压缩20M文件从30秒到1秒的优化过程 有一个需求需要将前端传过来的10张照片&#xff0c;然后后端进行处理以后压缩成一个压缩包通过网络流传输出去。之前没有接触过用Java压缩文件的&#xff0c;所以就直接上网找了一个例子改了一下用了&#xff0c;改完以后也能使用&#xff0…

(考研湖科大教书匠计算机网络)第四章网络层-第九节:虚拟专用网与网络地址转换

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一&#xff1a;虚拟专用网&#xff08;1&#xff09;虚拟专用网是什么&#xff08;2&#xff09;虚拟专用网如何分配IP地址&#xff08;3&#xff09;例子&#x…

【JAVA八股文】框架相关

框架相关1. Spring refresh 流程2. Spring bean 生命周期3. Spring bean 循环依赖解决 set 循环依赖的原理4. Spring 事务失效5. Spring MVC 执行流程6. Spring 注解7. SpringBoot 自动配置原理8. Spring 中的设计模式1. Spring refresh 流程 Spring refresh 概述 refresh 是…

深度学习(1)神经网络基础

要学习深度学习&#xff0c;那么首先要熟悉神经网络&#xff08;Neural Networks&#xff0c;简称NN&#xff09;的一些基本概念。当然&#xff0c;这里所说的神经网络不是生物学的神经网络&#xff0c;我们将其称之为人工神经网络&#xff08;Artificial Neural Networks&…

海豚调度2.0.5 星环驱动包踩坑(二)worker服务正常、zk注册正常,心跳时间不更新,也不执行任务,任务一直处于执行中状态

目录背景问题记录20230206 发现服务启动失败20230215 有一台worker不执行作业&#xff0c;其它均正常问题解决问题思考背景 之前分享过海豚调度2.0.5连接星环库使用记录&#xff0c;后来说存储过程又出现了超时的情况&#xff0c;原因是因为调度星环驱动包和生产星环库驱动包不…

ES 异常写入解决流程

问题说明 一天下午&#xff0c;在北京客户现场的同学反馈我们elasticsearch出现的大量的异常&#xff0c;他反馈说他使用多线程写入大量数据到elasticsearch集群时&#xff0c;隔一段时间之后就会出现CircuitBreakingException&#xff0c;多尝试几次后&#xff0c;他就把问题反…

基于微信小程序的微信社团小程序

文末联系获取源码 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏览器…

JavaEE|网络原理·上

文章目录一、网络发展史1.独立模式2.网络互联3.局域网&#xff08;LAN&#xff09;4.广域网&#xff08;WAN&#xff09;局域网组网的方式①基于网线直连②基于集线器&#xff08;hub&#xff09;组建③基于交换机(switch)组建④基于交换机和路由器组建二、网络通信基础1.ip地址…

Winform控件开发(14)——NotifyIcon(史上最全)

前言: 先看个气泡提示框的效果: 代码如下: 在一个button中注册click事件,当我们点击button1时,就能显示气泡 private void button1_Click(object sender, EventArgs e){notifyIcon1.Visible = true;notifyIcon1

【论文速递】ICLR2018 - 用于小样本语义分割的条件网络

【论文速递】ICLR2018 - 用于小样本语义分割的条件网络 【论文原文】&#xff1a;CONDITIONAL NETWORKS FOR FEW-SHOT SEMANTIC SEGMENTATION&#xff08;Workshop track - ICLR 2018&#xff09; 【作者信息】&#xff1a;Kate Rakelly Evan Shelhamer Trevor Darrell Alexe…

PyTorch - Conv2d 和 MaxPool2d

文章目录Conv2d计算Conv2d 函数解析代码示例MaxPool2d计算函数说明卷积过程动画Transposed convolution animationsTransposed convolution animations参考视频&#xff1a;土堆说 卷积计算 https://www.bilibili.com/video/BV1hE411t7RN 关于 torch.nn 和 torch.nn.function t…

Reverse入门[不断记录]

文章目录前言一、[SWPUCTF 2021 新生赛]re1二、[SWPUCTF 2021 新生赛]re2三、[GFCTF 2021]wordy[花指令]四、[NSSRound#3 Team]jump_by_jump[花指令]五、[NSSRound#3 Team]jump_by_jump_revenge[花指令]前言 心血来潮&#xff0c;想接触点Reverse&#xff0c;感受下Reverse&am…

网络编程(一)

网络编程 文章目录网络编程前置概念1- 字节序高低地址与高低字节高低地址&#xff1a;高低字节字节序大端小端例子代码判断当前机器是大端还是小端为何要有字节序字节序转换函数需要字节序转换的时机例子一例子二2- IP地址转换函数早期(不用管)举例现在与字节序转换函数相比:**…

模块化热更思路

title: 模块化热更思路 categories: Others tags: [热更, 模块化, 分包] date: 2023-02-18 01:04:57 comments: false mathjax: true toc: true 模块化热更 浅浅的记录一下访问破 200w (But, I don’t care about this.) 前篇 只谈思路, 不贴实现代码. 需求 游戏类型属于合集…