canvas 曲线图 双数值轴 山峰图

下面的代码本人亲自撰写,原生不易啊。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><canvas id="myCanvas" width="400" height="300"></canvas>
</body><script>class MyCanvas {static dom = null;static ctx = null;static canvasWidth = 0;static canvasHeight = 0;static config = null;static valx = 0;static valy = 0;static xlist = [];static ylist = [];static lenTrue = 0;init(dom) {MyCanvas.dom = domMyCanvas.ctx = MyCanvas.dom.getContext('2d');MyCanvas.canvasWidth = MyCanvas.ctx.canvas.width;MyCanvas.canvasHeight = MyCanvas.ctx.canvas.height;}// 配置参数setOption(config) {MyCanvas.ctx.clearRect(0, 0, MyCanvas.dom.width, MyCanvas.dom.height);MyCanvas.config = configMyCanvas.xlist = config.series.data.map(e => e[0]);MyCanvas.ylist = config.series.data.map(e => e[1]);MyCanvas.valx = MyCanvas.x1valjpx()MyCanvas.valy = MyCanvas.y1valjpx()MyCanvas.ctx.lineWidth = 1;MyCanvas.xGraduate()MyCanvas.xDashedLine()MyCanvas.yGraduate()MyCanvas.yDashedLine()MyCanvas.curve()}static getRandomColor() {let color = `hsl(${Random(0, 360)},${Random(50, 100)}%,${Random(20, 60)}%)`function Random(min, max) {return Math.round(Math.random() * (max - min)) + min;}return color}// 绘制曲线static curve() {const left = MyCanvas.config.grid.leftconst curvature = MyCanvas.config.series.curvature// xhb:曲线两个落点都是y轴最大的px值const xhb = MyCanvas.canvasHeight - 20MyCanvas.ctx.beginPath();MyCanvas.ctx.setLineDash([]);MyCanvas.ylist.forEach((e, i) => {MyCanvas.ctx.strokeStyle = MyCanvas.getRandomColor();MyCanvas.ctx.lineWidth = 3;// xy是控制点的xy坐标const x = MyCanvas.xlist[i] * MyCanvas.valx + leftconst y = e * MyCanvas.valy * 2const line = new Path2D();line.name = MyCanvas.config.series.data[i][2]line.moveTo(x - curvature, xhb);line.quadraticCurveTo(x, xhb - y, x + curvature, xhb);MyCanvas.ctx.stroke(line);MyCanvas.dom.addEventListener("mousemove", (event) => {const isPointInPath = MyCanvas.ctx.isPointInStroke(line, event.offsetX, event.offsetY);if (isPointInPath) {// 曲线被悬浮console.log(line);}});})}// 求x轴每一份值对应了多少实际px值static x1valjpx() {const max = Math.max(...MyCanvas.xlist)const interval = MyCanvas.config.xAxis.intervalconst curvature = MyCanvas.config.series.curvature// 总间隔数const len = Math.ceil(max / interval)// 总值数const valz = len * intervalconst left = MyCanvas.config.grid.leftconst right = MyCanvas.config.grid.rightconst xw = MyCanvas.canvasWidth - left - right// 求出每一份x值对应的图表里面的x轴px数值const valx = xw / valzconst maxql = max * valx + curvatureif (maxql > xw) {// 说明最大x将会超出可画范围,需要增加竖线let lenTrue = lenlet maxqlTrue = maxqllet valxTrue = valxwhile (maxqlTrue > xw) {lenTrue++// 总值数const valz = lenTrue * interval// 求出每一份x值对应的图表里面的y轴px数值valxTrue = xw / valzmaxqlTrue = max * valxTrue + curvature}MyCanvas.lenTrue = lenTruereturn valxTrue}return valx}// 求y轴每一份值对应了多少实际px值static y1valjpx() {const max = Math.max(...MyCanvas.ylist)const interval = MyCanvas.config.yAxis.intervalconst curvature = MyCanvas.config.series.curvature// 总间隔数const len = Math.ceil(max / interval)// 总值数const valz = len * intervalconst top = MyCanvas.config.grid.topconst bottom = MyCanvas.config.grid.bottomconst xh = MyCanvas.canvasHeight - top - bottom// 求出每一份y值对应的图表里面的y轴px数值return xh / valz}// 绘制x轴刻度值,从左到右画static xGraduate() {const grid = MyCanvas.config.gridconst xAxis = MyCanvas.config.xAxisconst gridLen = Object.keys(grid).lengthconst curvature = MyCanvas.config.series.curvatureMyCanvas.ctx.beginPath();MyCanvas.ctx.strokeStyle = '#000';MyCanvas.ctx.textAlign = "center";MyCanvas.ctx.textBaseline = "top";MyCanvas.ctx.font = "14px Arial";if (gridLen) {const left = MyCanvas.config.grid.leftconst right = MyCanvas.config.grid.rightconst top = MyCanvas.config.grid.topconst bottom = MyCanvas.config.grid.bottomconst interval = MyCanvas.config.xAxis.intervallet len = 0if (MyCanvas.lenTrue) {len = MyCanvas.lenTrue} else {const max = Math.max(...MyCanvas.lxList)len = Math.ceil(max / interval)}const xw = MyCanvas.canvasWidth - left - rightconst jg = xw / lenfor (let i = 0; i < len + 1; i++) {if (i) {MyCanvas.ctx.fillText(interval * i, left + (jg * i), MyCanvas.canvasHeight - bottom + xAxis.kdjl)}}}}// 绘制x刻度虚线,从右到左画static xDashedLine() {const grid = MyCanvas.config.gridconst gridLen = Object.keys(grid).lengthconst curvature = MyCanvas.config.series.curvatureMyCanvas.ctx.beginPath();MyCanvas.ctx.strokeStyle = MyCanvas.config.xAxis.dashedColor;MyCanvas.ctx.setLineDash([3, 2]);if (gridLen) {const left = MyCanvas.config.grid.leftconst right = MyCanvas.config.grid.rightconst top = MyCanvas.config.grid.topconst bottom = MyCanvas.config.grid.bottomconst interval = MyCanvas.config.xAxis.intervallet len = 0if (MyCanvas.lenTrue) {len = MyCanvas.lenTrue} else {const max = Math.max(...MyCanvas.lxList)len = Math.ceil(max / interval)}// x方向可画范围pxconst xw = MyCanvas.canvasWidth - left - rightconst jg = xw / lenfor (let i = 0; i < len + 1; i++) {MyCanvas.ctx.moveTo(MyCanvas.canvasWidth - right - (jg * i), MyCanvas.canvasHeight - bottom);MyCanvas.ctx.lineTo(MyCanvas.canvasWidth - right - (jg * i), top);}}MyCanvas.ctx.stroke();}// 绘制y刻度虚线,从下到上画static yDashedLine() {const grid = MyCanvas.config.gridconst gridLen = Object.keys(grid).lengthMyCanvas.ctx.beginPath();MyCanvas.ctx.strokeStyle = MyCanvas.config.yAxis.dashedColor;MyCanvas.ctx.setLineDash([3, 2]);if (gridLen) {const left = MyCanvas.config.grid.leftconst right = MyCanvas.config.grid.rightconst top = MyCanvas.config.grid.topconst bottom = MyCanvas.config.grid.bottomconst max = Math.max(...MyCanvas.ylist)const interval = MyCanvas.config.yAxis.intervalconst len = Math.ceil(max / interval)const xh = MyCanvas.canvasHeight - top - bottomconst jg = xh / lenfor (let i = 0; i < len + 1; i++) {MyCanvas.ctx.moveTo(left, MyCanvas.canvasHeight - bottom - (jg * i));MyCanvas.ctx.lineTo(MyCanvas.canvasWidth - right, MyCanvas.canvasHeight - bottom - (jg * i));}}MyCanvas.ctx.stroke();}// 绘制y刻度值,从下到上画static yGraduate() {const grid = MyCanvas.config.gridconst yAxis = MyCanvas.config.yAxisconst gridLen = Object.keys(grid).lengthMyCanvas.ctx.beginPath();MyCanvas.ctx.strokeStyle = '#000';MyCanvas.ctx.textAlign = "right";MyCanvas.ctx.textBaseline = "middle";MyCanvas.ctx.font = "14px Arial";if (gridLen) {const left = MyCanvas.config.grid.leftconst right = MyCanvas.config.grid.rightconst top = MyCanvas.config.grid.topconst bottom = MyCanvas.config.grid.bottomconst max = Math.max(...MyCanvas.ylist)const interval = MyCanvas.config.yAxis.intervalconst len = Math.ceil(max / interval)const xh = MyCanvas.canvasHeight - top - bottomconst jg = xh / lenfor (let i = 0; i < len + 1; i++) {if (i == 0) {MyCanvas.ctx.fillText(0, left - yAxis.kdjl, MyCanvas.canvasHeight - bottom)} else {MyCanvas.ctx.fillText(interval * i, left - yAxis.kdjl, MyCanvas.canvasHeight - bottom - (jg * i))}}}}}const myCanvas = document.querySelector('#myCanvas');const canvas = new MyCanvas()canvas.init(myCanvas)canvas.setOption({grid: {top: 20,right: 20,bottom: 20,left: 40,},yAxis: {dashedColor: '#000',kdjl: 8, // 刻度与轴线距离interval: 5, // 每条虚线间隔(单位不是px,而是数值,对应刻度值距离值)},xAxis: {dashedColor: '#000',kdjl: 8, // 刻度与轴线距离interval: 5, // 每条虚线间隔(单位不是px,而是数值,对应刻度值距离值)},series: {curvature: 20,// 曲线曲率单位pxdata: [[10, 20, '信号1'], [8, 23, '信号2'], [15, 30, '信号3'], [25, 10, '信号4'], [44, 58, '信号5']]}})
</script></html>

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS3 用户界面、图片、按钮

一、CSS3用户界面&#xff1a; 在CSS3中&#xff0c;增加了一些新的用户界面特性来调整元素尺寸、框尺寸和外边框。CSS3用户界面属性&#xff1a;resize、box-sizing、outline-offset。 1、resize&#xff1a; resize属性指定一个元素是否应该由用户去调整大小。 <style…

Azure 机器学习 - 有关为 Azure 机器学习配置 Kubernetes 群集的参考

目录 受支持的 Kubernetes 版本和区域建议的资源计划ARO 或 OCP 群集的先决条件禁用安全增强型 Linux (SELinux)ARO 和 OCP 的特权设置 收集的日志详细信息Azure 机器学习作业与自定义数据存储连接支持的 Azure 机器学习排斥和容许最佳实践 通过 HTTP 或 HTTPS 将其他入口控制器…

DAY50 309.最佳买卖股票时机含冷冻期 + 714.买卖股票的最佳时机含手续费

309.最佳买卖股票时机含冷冻期 题目要求&#xff1a;给定一个整数数组&#xff0c;其中第 i 个元素代表了第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;: 你不…

vue2+elementui使用MessageBox 弹框$msgbox自定义VNode内容:实现radio

虽说实现下面的效果&#xff0c;用el-dialog很轻松就能搞定。但是这种简单的交互&#xff0c;我更喜欢使用MessageBox。 话不多说&#xff0c;直接上代码~ <el-button type"primary" size"mini" click"handleApply()" >处理申请</el-b…

【Git】Git图形化工具SSH协议IDEA集成Git的使用讲解

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《Git》。&#x1f3af;&#x1f3af; &#x1f449…

git命令之遭遇 ignore罕见问题解决

我先来讲讲背景 我的一些文件在ignore了&#xff0c;不会被提交到远程仓库&#xff0c;这时候我的远程仓库中是没有这几个文件的&#xff0c;这时候我如果使用 git reset 的话这时候除了那几个 ignore 的文件以外都被更新的&#xff0c;但是如果我不需要这几个被 ignore 的文件…

蓝桥杯之模拟与枚举day1

Question1卡片(C/CA组第一题) 这个是一道简单的模拟枚举题目&#xff0c;只要把对应每次的i的各个位都提取出来&#xff0c;然后对应的卡片数目减去1即可。属于打卡题目。注意for循环的特殊使用即可 #include <iostream> using namespace std; bool solve(int a[],int n…

NSS [鹏城杯 2022]压缩包

NSS [鹏城杯 2022]压缩包 考点&#xff1a;条件竞争/逻辑漏洞&#xff08;解压失败不删除已经解压文件&#xff09; 参考&#xff1a;回忆phpcms头像上传漏洞以及后续影响 | 离别歌 (leavesongs.com) 源码有点小多 <?php highlight_file(__FILE__);function removedir($…

大模型+人形机器人,用AI唤起钢筋铁骨

《经济参考报》11月8日刊发文章《多方布局人形机器人赛道,智能应用前景广》。文章称&#xff0c;工信部日前印发的《人形机器人创新发展指导意见》&#xff0c;按照谋划三年、展望五年的时间安排&#xff0c;对人形机器人创新发展作了战略部署。 从开发基于人工智能大模型的人…

CCLink转Modbus TCP网关_MODBUS报文配置

兴达易控CCLink转Modbus TCP网关是一种功能强大的设备&#xff0c;可实现两个不同通信协议之间的无缝对接。它能够将CCLink协议转换为Modbus TCP协议&#xff0c;并通过报文配置实现灵活的通信设置。兴达易控CCLink转Modbus TCP网关可以轻松实现CCLink和Modbus TCP之间的数据转…

汇编-EQU伪指令(数值替换)

EQU伪指令将一个符号名称与一个整数表达式或一个任意文本相关联&#xff0c; 它有3种格式 在第一种格式中&#xff0c; expression必须是一个有效的整数表达式。在第二种格式中&#xff0c; symbol是一个已存在的符号名称&#xff0c; 已经用或EQU定义过。在第三种格式中&…

新方向!文心一言X具身智能,用LLM大模型驱动智能小车

具身智能已成为近年来研究的热点领域之一。具身智能强调将智能体与实体环境相结合&#xff0c;通过智能体与环境的交互&#xff0c;来感知和理解世界&#xff0c;最终实现在真实环境中的自主决策和运动控制。 如何基于文心大模型&#xff0c;低成本入门“具身智能”&#xff0…

GEE:将鼠标变成十字指针,点击获取影像值,显示值到UI中

作者:CSDN @ _养乐多_ 本文记录了在 Google Earth Engine(GEE)开发中,将鼠标变成十字指针,点击获取影像值,显示值到UI中的代码片段。这段代码复制过去修改变量名就可以用了。 效果如下图所示, 文章目录 一、代码片段一、代码片段 使用的时候将 YLDImage 变量换成你屏…

【网络协议】

网络协议 1 网络通讯1.1 防火墙1.2 子网掩码1.3 网关1.4 2 SSH2.1 SSH2.2 SSH12.3 SSH2 3 Telnet4 Telnet/SSL5 NFS6 TFTP7 FTP8 SFTP9 HTTP10 HTTPS11 NAT12 加密 1 网络通讯 1.1 防火墙 所谓“防火墙”&#xff0c;是指一种将内部网和公众访问网(如Internet)分开的方法&…

C# OpenCvSharp 环形文字处理 直角坐标与极坐标转换

效果1 效果2 项目 代码 using OpenCvSharp; using System; using System.Drawing; using System.Text; using System.Windows.Forms;namespace OpenCvSharp_Demo {public partial class frmMain : Form{public frmMain(){InitializeComponent();}string fileFilter "*.*…

2020年五一杯数学建模A题煤炭价格预测问题解题全过程文档及程序

2020年五一杯数学建模 A题 煤炭价格预测问题 原题再现 煤炭属于大宗商品&#xff0c;煤炭价格既受国家相关部门的监管&#xff0c;又受国内煤炭市场的影响。除此之外&#xff0c;气候变化、出行方式、能源消耗方式、国际煤炭市场等其他因素也会影响煤炭价格。请完成如下问题。…

VR虚拟现实:VR技术如何进行原型制作

VR虚拟现实原型制作 利用VR虚拟现实软件进行原型制作可以用于增强原型测试期间的沉浸感&#xff0c;减少产品设计迭代次数&#xff0c;并将与产品原型制作相关的成本降低40-65%。 VR虚拟现实原型制作市场规模 用于原型制作的虚拟现实 (VR) 市场在 2017 年估计为 2.104 亿美元…

中文编程软件视频推荐,自学编程电脑推荐,中文编程开发语言工具下载

中文编程软件视频推荐&#xff0c;自学编程电脑推荐&#xff0c;中文编程开发语言工具下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件…

2020年上半年信息安全工程师下午案例题及解析

2020年因为疫情&#xff0c;计划是上半年考&#xff0c;改为下半年考&#xff0c;但题目是上半年已经出好了的&#xff0c;所以还是第一版教材的内容。 如大家在学习中遇到问题&#xff0c;欢迎通过邮件2976033qq.com留言给作者&#xff0c;以便共同探讨。 试题一&#xff08…

Java类和对象(续)

书接上回我们已经学完了对象的初始化&#xff0c;今天的内容更加精彩。 1.封装 面向对象程序的三大特征&#xff1a;封装&#xff0c;继承&#xff0c;多态。 本章主要也是要研究封装&#xff0c;简单来说就是套壳屏蔽细节。 封装的概念&#xff1a; 封装&#xff1a;将数据和…