#夏日挑战赛# HarmonyOS 实现一个手绘板
Posted 开源基础软件社区官方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#夏日挑战赛# HarmonyOS 实现一个手绘板相关的知识,希望对你有一定的参考价值。
前言
最近在学习openHarmony,恰好之前了解过canvas,所以本篇文章分享一下我实现的一个手绘板,利用openHarmony内置的API cnavas组件实现。
介绍
这是一个手绘板,并且可以根据滑动屏幕速度,动态生成线条大小,当用户触摸屏幕,会生成线条,并且速度越快,线条越细。
效果展示
原理分析
1.绘制原理
首先,我们需要将canvas上下文对象,需要在触摸移动事件中绑定,因为我们是通过触摸来生成对应线条的。
然后,属性选择lineCap,属性值有三种:butt、round、square,我尝试了后发现round效果比较好。
最后将数组中的最后一个值取出,作为moveTo的坐标,将鼠标移动后的点作为lineTo的坐标,然后再通过stroke就能绘制出图像。
const el = this.$refs.canvas;
this.ctx = el.getContext(2d)
this.ctx.lineWidth =this.lineWidth/2
this.ctx.beginPath()
// 向线条的每个末端添加圆形线帽。
this.ctx.lineCap = square
// 每次将数组中最后一个值取出,作为起始点
this.ctx.moveTo(this.ArrX[this.ArrX.length-1],this.ArrY[this.ArrY.length-1])
this.ctx.lineTo(e.touches[0].localX,e.touches[0].localY)
this.ctx.stroke()
this.ArrX.push(e.touches[0].localX)
this.ArrY.push(e.touches[0].localY)
2.线条粗细
当触发touchmove事件,将当前时间戳存储起来,通过上一次触发事件获得的时间-当前触发事件获得的时间,就可以得到两次触发事件的事件间隔,此时我们就获得了两点之间的时间
再计算两点之间的距离(平方和再开根号),通过 路程/时间 = 速度
计算出两点之间的速度,从而可以动态生成线条粗细
// 计算线条粗细
const currTime = Date.now()
if(this.startTime !== 0)
const duration = currTime - this.startTime
// 传入倒数第二个点和最后一个点,和持续时间,会返回加速度
const v = this.speed(this.ArrX[this.ArrX.length-2],this.ArrY[this.ArrY.length-2],this.ArrX[this.ArrX.length-1],this.ArrY[this.ArrY.length-1],duration)
this.lineWidth = this.lineWidth/v
if(this.lineWidth>25)
this.lineWidth = 25
if(this.lineWidth<1)
this.lineWidth = 1
this.startTime = currTime
完整代码
index.js
// @ts-nocheck
export default
data:
ctx:,
ArrX:[],
ArrY:[],
// 开始时间
startTime:0,
lineWidth:14
,
// 偏移很多
touchstart(e)
// 开始时间清空
this.startTime = 0
this.ArrX.push(e.touches[0].localX)
this.ArrY.push(e.touches[0].localY)
,
// 计算最后两点的速度
speed(x1,y1,x2,y2,s)
const x = Math.abs(x1-x2)*Math.abs(x1-x2)
const y = Math.abs(y1-y2)*Math.abs(y1-y2)
return Math.sqrt(x+y)/s
,
touchmove(e)
// 计算线条粗细
const currTime = Date.now()
if(this.startTime !== 0)
const duration = currTime - this.startTime
// 传入倒数第二个点和最后一个点,和持续时间,会返回加速度
const v = this.speed(this.ArrX[this.ArrX.length-2],this.ArrY[this.ArrY.length-2],this.ArrX[this.ArrX.length-1],this.ArrY[this.ArrY.length-1],duration)
this.lineWidth = this.lineWidth/v
if(this.lineWidth>25)
this.lineWidth = 25
if(this.lineWidth<1)
this.lineWidth = 1
this.startTime = currTime
const el = this.$refs.canvas;
this.ctx = el.getContext(2d)
this.ctx.lineWidth =this.lineWidth/2
this.ctx.beginPath()
// 向线条的每个末端添加圆形线帽。
this.ctx.lineCap = square
// 每次将数组中最后一个值取出,作为起始点
this.ctx.moveTo(this.ArrX[this.ArrX.length-1],this.ArrY[this.ArrY.length-1])
this.ctx.lineTo(e.touches[0].localX,e.touches[0].localY)
this.ctx.stroke()
this.ArrX.push(e.touches[0].localX)
this.ArrY.push(e.touches[0].localY)
,
touchend(e)
this.startTime = 0
index.hml
<div class="container">
<canvas ref="canvas" class="canvas" @touchstart="touchstart"
@touchmove="touchmove" @touchend="touchend"/>
</div>
index.css
.container
margin: 50px;
.canvas
height: 100%;
width: 100%;
background-color: #eee;
border: 1px solid #ffc300;
总结
以上是关于#夏日挑战赛# HarmonyOS 实现一个手绘板的主要内容,如果未能解决你的问题,请参考以下文章
#夏日挑战赛# HarmonyOS - 自定义组件之slider滑块
#夏日挑战赛# HarmonyOS - 实现带日期效果的待办事项