1.创建 canvas 绘图上下文(指定 canvasId)

定义:在自定义组件下,第二个参数传入组件实例this,以操作组件内 canvas 组件。需要指定 canvasId,该绘图上下文只作用于对应的 canvas。

参数

参数 类型 说明
canvasId String 画布表示,传入定义在 canvas组件的 canvas-id或id(支付宝小程序是id、其他平台是canvas-id)
componentInstance Object 自定义组件实例 this ,表示在这个自定义组件下查找拥有 canvas-id 的 canvas组件 ,如果省略,则不在任何自定义组件内查找

返回值
CanvasContext

具体可查看文档,由于我自己的项目需要画个振动波型曲线图,所以我的实现方式如下:

2.通过uni.connectSocket,创建一个 WebSocket 连接。(波形图的父页面)

<template><view><!-- 振动波型图组件 --><curve ref="otdrCurve" cid="otdr-curve" class="charts"></curve><!-- 调整距离 --><view class="slider-range"><!-- 滑动条插件 --><slider-range:bar-height="8":block-size="30":decorationVisible="true":format="format":max="rangMax":min="0":step="1":value="range"@change="handleRangeChange"/></view></view>
</template>
<script>
import { ACCESS_TOKEN } from '@/common/util/constants'
import { getBaseUrl } from '@/common/service/config.js'
import { http } from '@/common/service/service.js'
import curve from './curve'
// 定义滑动条的最大距离
let maxDistance = 40 * 1000
// 曲线数据(全局变量)
let curveData = {start: 0,end: maxDistance,data: [],markLine: []
}
export default {components: {curve},data() {return {start: 0,end: 0,socketTask:{},rangMax: maxDistance,range: [0, maxDistance],getData: null, //用于接收防抖函数的返回值}},mounted() {// console.log('端口波形 mounted')this.$refs.otdrCurve.setStartEnd(this.start, this.end)this.drawChart()this.connectSocketInit()// 接收防抖函数(因为滑动条触发抖动,因此加个防抖函数处理)this.getData = this.rangeDebounce(this.changeCalibrateDis, 500)},// 实例销毁之前调用beforeDestroy() {// 实例销毁前清空敲击的波形图curveData.markLine = []this.closeSocket()},methods: {// 进入这个页面的时候创建websocket连接【整个页面随时使用】connectSocketInit() {let token = uni.getStorageSync(ACCESS_TOKEN)//用户tokenlet url = getBaseUrl().replace('https://', 'ws://').replace('http://', 'ws://')url = url + '/ifcs/websocket/wave/' + token + '/' + this.task.devicecodeconsole.log('url', url)//这里的url需要跟后端商量都要拼接什么标识进行连接this.socketTask = uni.connectSocket({//此API返回一个 socketTask 对象url: url,//服务器接口地址success(data) {console.log('websocket连接成功', data)}})this.socketTask.onMessage(this.onMessage)this.socketTask.onOpen(() => {console.log('WebSocket连接正常打开中...!')})this.socketTask.onError(e => {console.log('WebSocket onError', e)})this.socketTask.onClose(() => {console.log('WebSocket已经被关闭了!')})},//WebSocket 接受到服务器的消息事件的回调函数onMessage(e) {const data = eval('(' + e.data + ')')//data   String/ArrayBuffer  服务器返回的消息if (data.type === 'shakedata' && data.originalDataList) {//更新最大长度if (data.maxlength && maxDistance !== data.maxlength) {maxDistance = data.maxlengththis.rangMax = data.maxlengththis.range[1] = data.maxlengththis.end = data.maxlength}// 波形let array = data.originalDataListlet length = data.originalDataList.length// console.log('波形length: ' + length)if (length > 0) {const temp = []//计算数据抽取力度let points = 300 //图表内显示的点数let step = 10if (length > points) {step = length / points}step = Math.floor(step)//曲线波形数据for (let i = 0; i < length - step; i += step) {temp.push(array[i])}curveData.data = temp}}this.drawChart()},// 传入数据到波形图/点时域图组件drawChart() {this.$refs.otdrCurve.drawChart(curveData)},// 关闭websocket【离开这个页面的时候执行关闭】closeSocket() {if (this.socketTask) {this.socketTask.close({})}},//滑动条格式format(val) {return val + '米'},// 调整距离handleRangeChange(e) {this.start = e[0]this.end = e[1]curveData.start = e[0]curveData.end = e[1]this.getData(e)},//更改敲击标定距离changeCalibrateDis() {http.post('/ifcs/calibrate/changeCalibrateDis', {//更改距离后及时调用接口请求最新数据taskid: this.task.id,devicecode: this.task.devicecode,startdistance: this.start,enddistance: this.end}).then(res => {const {startdistance,enddistance} = res.config.datacurveData.start = startdistancecurveData.end = enddistancethis.start = startdistancethis.end = enddistance})},}
}
</script>
<style scoped>
.charts {width: 100%;height: 200px;
}
</style>

3.画波形图(波形图的子页面)(创建一个名为curve.vue文件,可以跟父级页面同级方便调用,引用路径不用那么长)

<template><view><canvas :canvas-id="cid" :id="cid" :style="`width: ${width}px; height: ${height}px;`" @click="onClick"></canvas></view>
</template><script>
//这里需要安装d3
import * as d3 from 'd3'const fontSize = 12//字体大小
const padding = 22//内边距
const line1Color = '#0a2db8'//振动曲线的颜色
const line2Color = '#c20909'//敲击振动曲线的颜色
const bgColor = '#fff'//画布背景颜色
const gridColor = '#ccc'//网格的颜色
const axisColor = '#666'//X轴的颜色
const lineWidth = 0.5//线宽
const gridWidth = 1//网格的宽度
const seqColors = ['#06F506', '#c20909', '#0a2db8']//点时域曲线的颜色
export default {name: 'curve',props: {cid: {type: String,default: 'curve'},curve: {type: Object,default: () => ({})},xLabel: {type: String,default: '位置(m)'},points: {type: Array,default: function() {return [0, 0, 0]}}},data() {return {width: 300,//画布宽度height: 200,//画布高度max: 70,//y轴最大距离min: 0,//y轴最小距离yStep: 10,//y轴间隔start: 0,//x轴开始距离end: 800000//x轴结束距离}},computed: {scaleValue() {return d3.scaleLinear().domain([padding, this.width - padding]).range([this.start, this.end])},xAxis() {return d3.scaleLinear().domain([this.start, this.end]).range([padding, this.width - padding])},yAxis() {return d3.scaleLinear().domain([this.min, this.max]).range([padding, this.height - padding])}},created() {// console.log('created ' + this.cid)// 获取窗口宽高const { windowWidth } = uni.getSystemInfoSync()this.width = windowWidth// console.log(this.width, this.height)},mounted() {// console.log('mounted ' + this.cid)this.ctx = uni.createCanvasContext(this.cid, this)},methods: {//曲线位置点击事件onClick(e) {// console.log('onClick', e.target.x, e.target.y)//这里能获取到你点击曲线的位置信息,便于后续显示数据let { x, y } = e.targetthis.$emit('curveClick', this.scaleValue(x))//传到父级页面使用},//获取父页面传过来的X轴的起始距离和结束距离setStartEnd(start, end) {this.start = startthis.end = end},//绘制图表总事件drawChart(curve) {this.start = curve.startthis.end = curve.endthis.drawBackground()this.drawGrid()this.drawAxis()this.drawLegend()this.drawCurve(curve)this.drawMarkLine(curve)this.ctx.draw()},//绘制画布背景色drawBackground() {// console.log('drawBackground')const { ctx, width, height } = thisctx.beginPath()ctx.setFillStyle(bgColor)ctx.fillRect(0, 0, width, height)ctx.fill()},//绘制网格线drawGrid() {// console.log('drawGrid')const { ctx, yStep, min, max, width, height, xAxis, yAxis } = thisctx.beginPath()// ctx.setLineCap('round')ctx.setStrokeStyle(gridColor)ctx.setLineWidth(gridWidth)//绘制横向网格let count = max / yStep// console.log('count', count)let x = width - paddingfor (let i = 1; i <= count; i++) {let y = yAxis(max - i * yStep)ctx.moveTo(padding, y)ctx.lineTo(x, y)}//绘制纵向网格let ticks = xAxis.ticks(5)let y = height - paddingfor (let i = 0; i < ticks.length; i++) {let x = xAxis(ticks[i])ctx.moveTo(x, y)ctx.lineTo(x, padding)}ctx.stroke()//用 stroke() 方法来画线条//绘制y轴labelctx.beginPath()ctx.setFontSize(fontSize)ctx.setFillStyle('black')// ctx.fillText('0', padding - 6, height - padding + fontSize)ctx.fillText('衰耗(dB)', padding - 15, padding - 10)ctx.fillText(this.xLabel, width - 50, height - 30)for (let i = 0; i <= count; i++) {ctx.fillText('' + i * 10, padding - fontSize * 1.5, yAxis(max - i * 10) + fontSize / 2)}//绘制x轴labelfor (let i = 0; i < ticks.length; i++) {let num = ticks[i]let span = fontSize * 0.5if (num >= 10) {span = fontSize} else if (num >= 100) {span = fontSize * 1.5} else if (num >= 1000) {span = fontSize * 2} else if (num >= 10000) {span = fontSize * 2.5}ctx.fillText('' + ticks[i], xAxis(ticks[i]) - span, height - padding + fontSize + 2)}},//绘制X轴drawAxis() {// console.log('drawAxis')const { ctx, width, height } = thisctx.beginPath()ctx.setStrokeStyle(axisColor)ctx.setLineWidth(gridWidth)ctx.moveTo(padding, padding)ctx.lineTo(padding, height - padding)ctx.moveTo(padding, height - padding)ctx.lineTo(width - padding, height - padding)ctx.stroke()},// 绘制线条drawCurve(curve) {if (curve.data.length <= 0) {return}const { ctx, xAxis, yAxis, max, width } = thisconst data = curve.dataconst lineDataLen = data.lengthlet sp = data[0]ctx.beginPath()ctx.setLineCap('round')ctx.setStrokeStyle(line1Color)ctx.setLineWidth(lineWidth)ctx.moveTo(xAxis(sp[0]), yAxis(max - sp[1]))for (let i = 0; i < lineDataLen; i++) {let x = xAxis(data[i][0])let y = yAxis(max - data[i][1])if (x < padding || x > width - padding) continuectx.lineTo(x, y)}ctx.stroke()},//绘制敲击振动的曲线drawMarkLine(curve) {if (!curve.markLine || curve.markLine.length <= 0) {return}const { ctx, xAxis, yAxis, max, height } = thislet markLine = curve.markLinectx.beginPath()ctx.setStrokeStyle(line2Color)for (let i = 0; i < markLine.length; i++) {let x = xAxis(markLine[i][0])let y = yAxis(max - markLine[i][1])if (x < padding) continuectx.moveTo(x, height - padding)ctx.lineTo(x, y)}ctx.stroke()},//绘制点击振动曲线的图例drawLegend() {const { ctx, points, width } = thislet x = 60ctx.beginPath()for (let i = 0; i < points.length; i++) {ctx.setFillStyle(seqColors[i])ctx.fillRect(x, 2, fontSize, fontSize)x = x + fontSize + 2let t = points[i].toFixed(1) + '米'ctx.fillText(t, x, fontSize)let space = t.length * fontSizex = x + space - 10}}}
}
</script><style></style>

效果图如下:

用canvas画曲线图相关推荐

  1. 使用canvas画折线图和曲线图

    使用canvas画折线图和曲线图 贝塞尔曲线如果想要在p0=>p2的过程中经过p1,那么需要计算出pc的值,在canvas之中作为控制点 二次贝塞尔曲线转换为三次 上面只是简单介绍,具体的参考文 ...

  2. python画曲线图例-如何使用python画曲线图

    如何使用python画曲线图?下面是基本步骤: 前提 首先,为了实际使用 Matplotlib,我们需要安装它. 安装 如果你安装了更高版本的 Python,你应该能够打开cmd.exe或终端,然后执 ...

  3. python绘制曲线图-python怎么画曲线图

    如何使用python画曲线图?下面是基本步骤: 前提 首先,为了实际使用 Matplotlib,我们需要安装它. 安装 如果你安装了更高版本的 Python,你应该能够打开cmd.exe或终端,然后执 ...

  4. 微信小程序中base64格式的小程序码通过canvas画出来无效

    使用场景 小程序中的文章详情页面有一个分享功能:用户点击分享按钮,生成一张分享图片(包括封面图,简介以及带有文章ID的小程序码),方便用户保存在本地. 问题说明 小程序码通过后台接口获取,格式如下:' ...

  5. 关于星空的java小程序_[Java教程]小程序使用Canvas画饼图_星空网

    小程序使用Canvas画饼图 2018-10-24 0 先上效果图 -------------------------------------------------------------w --- ...

  6. python程序、画一个笑脸_如何使用canvas画一个微笑的表情(代码示例)

    本篇文章给大家带来的内容是关于如何使用canvas画一个微笑的表情(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 实习期间让我用canvas画一个表情,比较简单,话不多说 ...

  7. [html] 请使用canvas画一个椭圆

    [html] 请使用canvas画一个椭圆 <script> var c=document.getElementById("myCanvas"); var ctx=c. ...

  8. [html] 请使用canvas画一个渐变的长方形

    [html] 请使用canvas画一个渐变的长方形 // 普通canvas绘图工具类// umd适配多种引入方式 (function(root, factory) {if (typeof define ...

  9. python如何画曲线图_如何使用python画曲线图

    如何使用python画曲线图?下面是基本步骤: 前提 首先,为了实际使用 Matplotlib,我们需要安装它. 安装 如果你安装了更高版本的 Python,你应该能够打开cmd.exe或终端,然后执 ...

最新文章

  1. 使用JS/Jquery获得父窗口的几个方法(笔记)
  2. C++ 析构函数(函数前面有波浪号~)
  3. easyexcel工具类_阿里巴巴程序员常用的 15 款开发者工具
  4. MapReduce的自制Writable分组输出及组内排序
  5. mysql syncbinlog_Mysql之sync-binlog参数
  6. 专注jQurey的博客【2012年度IT博客大赛分类推荐】
  7. python format用法
  8. 乐佰小迪智能机器人怎么使用_425台云洲智能水面救生机器人在山东寿光投入使用...
  9. Eclipse CDT 编译wxWidgets
  10. 磁盘大小限制_Linux服务器磁盘爆满查询之百度云服务器
  11. Java WebSocket生命周期
  12. ThinkPHP 3 的输出
  13. Linux下编译安装WizNote
  14. 通俗易懂——5G调制方式全面解读
  15. 基于Hadoop的数据分析案例-陌陌聊天软件数据分析
  16. [system] Map key not configured
  17. 将文件夹中的图片按照文件名进行标签分类
  18. 【历史上的今天】9 月 9 日:C 语言之父诞生;阿里巴巴成立
  19. 钱符号怎么打出来(如何在文档中输入人民币符号?)
  20. krpano全景图切片还原和下载

热门文章

  1. 基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器
  2. 2018年春节拍的照片
  3. 竞标和招投标有什么区别
  4. 更换Ubuntu源为清华源
  5. 网站漏洞扫描的渗透测试方法
  6. Markdown语法补充---字号颜色表情流程图等
  7. 2020年中国市场主体新增注册量、新增注销量及发展政策建议分析[图]
  8. VMware vSAN两份文档
  9. 【VUE项目实战】37、商品分类功能介绍和基本结构搭建
  10. 红米1s 刷入魔趣 (Mokee)ROM(Android 7.1)