使用 konvas.js 完成 canvas 写字
效果图
思路
- 使用Konva.js 库 详细文档Konva.js
- stage 由 米字格 layer 和 字的 layer 构成
- 整体 字 的构成 由 线段 > 笔划 > 字
- 每个笔划 保存成 数组 历史记录
- 使用api 有 Konva.Stage() Konva.Layer() konva.Group() Konva.Line() Node.hide() Node.show() Canvas.toDataURL() .draw()
详细代码
<style>
#cvs{
width: 600px;
height: 600px;
margin:0 auto;
}
.tools{
padding: 30px;
width: 600px;
margin:0 auto;
display: flex;
justify-content: space-around;
}
.img-list{
display: flex;
}
.img-list img{
width: 100px;
height: 100px;
border:1px solid #ccc;
margin-right: 10px;
}
</style>
<body>
<div id='cvs'></div>
<div class="tools">
<label for="">
选取颜色:
<input type="color" id='color-picker'/>
</label>
<button class="clear">清空</button>
<button class="save">保存</button>
<button class="prev">上一笔</button>
<button class='next' >下一笔</button>
</div>
<div class="img-list">
</div>
</body>
<script>
var colorPicker = document.getElementById('color-picker')
var cvsEl = document.getElementById('cvs').getBoundingClientRect()
var stage = new Konva.Stage({
container:'cvs',
width: cvsEl.width,
height: cvsEl.height
})
var layer = new Konva.Layer() // 存放 米字格
var fontLayer = new Konva.Layer() // 存放 字 用于导出图片 分离米字格
var grid = new Konva.Group() // 米字格
var font = new Konva.Group() // 字
var fontHistory = [] // 记录字的每一个笔划 id
var lineIndex = -1 // 笔划 index
// 笔划最大宽度
var maxWidth = 30
var minWidth = 1
// 笔划速度
var maxSpeed = 10
var minSpeed = 0.1
// 初始化 上一次笔划宽度
var prevWidth = maxWidth
// 选取颜色
var color = '#333'
colorPicker.addEventListener('input',function(e){
color = e.target.value
},false)
// 清空 字
document.querySelector('.clear').addEventListener('click',function(){
font.destroyChildren()
fontLayer.draw()
lineIndex = -1
fontHistory.length = 0
})
// 保存 字 成图片
document.querySelector('.save').addEventListener('click',function(){
if(!fontHistory.length) return
var imgList = document.querySelector('.img-list')
var img = new Image()
img.src = fontLayer.canvas.toDataURL('png',1)
imgList.appendChild(img)
})
// 上一笔划
document.querySelector('.prev').addEventListener('click',function(){
if(!fontHistory.length || lineIndex === -1) return
font.findOne(`#${fontHistory[lineIndex--]}`).hide()
fontLayer.draw()
})
// 下一笔划
document.querySelector('.next').addEventListener('click',function(){
if(!fontHistory.length || lineIndex === fontHistory.length -1) return
lineIndex ++
font.findOne(`#${fontHistory[lineIndex]}`).show()
font.draw()
})
// 动态计算笔划宽度 使笔划 有粗细 过渡 顺滑
var calculateWidth = function(distance,speed){
var strokeWidth = 1
if(speed>= maxSpeed){
strokeWidth = minWidth
}else if( speed <= minSpeed){
strokeWidth = maxWidth
}else{
strokeWidth = (maxSpeed-speed) / (maxSpeed-minSpeed) * maxWidth
}
return prevWidth*3/4 + strokeWidth / 4
}
// 米字格
grid.add(new Konva.Line({
points: [0, 0, stage.width(),0, stage.width(),stage.height(), 0, stage.height(),0,0],
stroke: 'red',
strokeWidth: 5,
}),
new Konva.Line({
points: [0,stage.height()/2, stage.width(), stage.height()/2],
stroke:'red',
strokeWidth:2,
dash: [2, 2]
}),
new Konva.Line({
points: [0,0, stage.width(), stage.height()],
stroke:'red',
strokeWidth:2,
dash: [2, 2]
}),
new Konva.Line({
points: [stage.width(), 0, 0, stage.height()],
stroke:'red',
strokeWidth:2,
dash: [2, 2]
}),
new Konva.Line({
points: [stage.width()/2, 0 , stage.width()/2, stage.height()],
stroke:'red',
strokeWidth:2,
dash: [2, 2]
})
)
// 鼠标 事件 写字
stage.on('mousedown',function(){
var mousePos = stage.getPointerPosition();
var x = mousePos.x
var y = mousePos.y
this.isReady = true
this.start_x = x
this.start_y = y
this.timestamp = Date.now()
this.i ? null : this.i = 0
// 初始化 笔划线条
this.line = new Konva.Group({
id: 'line'+this.i++ ,
name:'line'
})
// 往字里 添加 笔划
font.add(this.line)
})
stage.on('mousemove',function(){
if(!this.isReady) return
var mousePos = stage.getPointerPosition();
var x = mousePos.x
var y = mousePos.y
var distance = Math.sqrt(Math.pow(x-this.start_x,2)+Math.pow(y-this.start_y,2))
var now = Date.now()
var speed = distance / ( now -this.timestamp) * 5
var strokeWidth = calculateWidth(distance,speed)
// 移动过程线段
this.current = new Konva.Line({
points:[this.start_x,this.start_y,x,y],
stroke:color,
strokeWidth,
lineCap: 'round',
lineJoin: 'round',
})
// 往笔划里添加 线段
this.line.add(this.current)
this.current.draw()
prevWidth = strokeWidth
this.timestamp = now
this.start_x = x
this.start_y = y
})
stage.on('mouseup mouseleave',function(){
if(this.isReady){
this.line.getChildren().length
? (fontHistory[++lineIndex] = this.line.id(), fontHistory.length = lineIndex+1 )
: this.line.destroy() ;
this.isReady = false
}
})
layer.add(grid)
fontLayer.add(font)
stage.add(layer,fontLayer)
layer.draw()
</script>
版权声明:本文为weixin_43978604原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。