效果图:
1、需求:
接口返回一个数组,每一项均是一个数字,代表着y坐标,x坐标需自己处理。
我的数据是1024个浮点数,在-10到10之间
波形图需要xy轴缩放功能,用c3的 transform: scale()是不行的,至少会失真。
然后背景的格子,我这里是每个格子要求100个点,初始缩放下是11个格子,10条线(竖线)
2、绘制所需的方法
1、创建canvas实例。
按uni-app文档所说,小程序的canvas需要一个唯一的canvas-id属性(属性名不同平台可能有差异,参照官网)以区分页面中不同的canvas。this则是vue实例。
let content = uni.createCanvasContext('waveform', this);
2、绘制格子
首先,调用uni.getSystemInfo获取屏幕宽度,这样就能根据不同屏幕来计算图形的xy坐标,做到每个屏幕的显示比例的都一样。换成父容器宽度也可,看你需求。
//横线
for (let i = -80; i <= 80; i += 20) {
content.moveTo(0, i);
content.lineTo(1100, i)
}
// 竖线
// 计算两条线之间的距离。windowWidth:屏幕宽度
let widthInterval = Number(this.windowWidth) / 11;
// x坐标缩放比例
let scalc = 100 / widthInterval;
for (let j = 1; j <= 10; j++) {
content.moveTo(j * widthInterval, -100);
content.lineTo(j * widthInterval, 100)
}
moveTo是将画笔移动到哪里。canvas画图就像我们画画,落笔之前首先要将笔尖移动到目标点。
lineTo传入一个坐标,然后将该坐标与上一次收笔的坐标连接起来,形成一条线。
示意图:
注意:moveTo仅移动画笔,不会绘制。lineTo才会绘制。
完成以上,仅仅是创建路径,相当于蓝图。下面将蓝图实现。
content.setStrokeStyle("#797979");
content.translate(0, 100);
content.stroke();
content.beginPath();
content.moveTo(0, 0)
第一个应该不用多说,设置线条颜色。
第二个,因为canvas坐标轴原点默认在左上角顶点,绘制过程中所有坐标点都是相对于该原点的,如果坐标有负数,则会超出canvas,像使用position超出盒子一样。所以使用该方法移动原点,我这里将y坐标向下移了100像素。
第三个,将当前描绘好的路径画成真的线条。实现蓝图的方法
第四个,至此,格子已经 画好了,由于格子跟图形是分开的,不能互相影响。调用此方法可以新建一个路径(canvas一开始就默认帮我们调用了一次)。
第五个,将画笔重新移动至原点。
3、绘制折线图
this.wave?.map((item, index) => {
content.lineTo(
(index / scalc),
(item * this.multipleList[this.currentMultiple] * 0.02))
})
content.setStrokeStyle("limegreen");
// content.translate(0, 100);
content.stroke();
content.draw(false)
wave是数据源
是这样的:因为我需求是每个格子100个点,1024个点共11个格子,如果一个数据点占据一个像素,那么就需要1024个像素,但移动端显然不可能这么大。于是,获取到屏幕宽度后,计算出比例,就可以得出每个坐标点占据的像素。
至于multipleList,则是缩放功能使用到的倍数列表。可自行决定。
最后一个方法:draw : 将上面所有东西绘制至canvas。通常在末尾调用。
3、结尾
整体难度不大,但如果不了解canvas绘图原理,还是很麻烦的,如果看不懂文章,建议先去官网看看,有更好的讲述。
还有一个小地方:坐标点有无限小数也无所谓,canvas会自动处理,些许差别肉眼看不出来。
最后,这是我加班没事干写着玩的,也是第一次写博客,写的不好请见谅。