一、画板2.0
2.0的效果图
方形
useSquare(){
// 一如既往的清空所有工具的事件监听器
this.clearAllTool()
if(this.toolStatus != 3){
this.toolStatus = 3
var x = 0,
y = 0;
var mouseMoveEvent = (e)=>{
if(this.throttleDate==0 || this.throttleDate+16<Date.now()){
// 清空上一次的涂鸦(未确定的存档),后续细讲
this.withdraw()
//根据x,y获取宽高
this.ctx.strokeRect(x, y, e.layerX-x,e.layerY-y);
}
}
this.squareEvents.down = (e) => {
x = e.layerX
y = e.layerY
// 使用图形工具,撤回的时候用到
this.openShape = true
this.ctx.strokeRect(x, y, 10,10);
this.canvas.addEventListener('mousemove',mouseMoveEvent)
}
this.squareEvents.up = (e) => {
this.openShape = false
this.canvas.removeEventListener('mousemove', mouseMoveEvent)
this.save()
}
this.canvas.addEventListener('mousedown', this.squareEvents.down);
this.canvas.addEventListener('mouseup', this.squareEvents.up)
}else{
// 关闭
this.toolStatus = 0
}
},
复制代码
思路和1.0的很相似,除了撤回函数改了,和频繁使用撤回函数
圆形
懂了这种圆之后,我们来看看椭圆
好了,虽然说圆我们用不到,但是有助于了解椭圆这个概念,角度偏移这一块我们暂时用不上,其他的就直接上手用了
useArc(){
this.clearAllTool()
if(this.toolStatus != 4){
this.toolStatus = 4
var x = 0,
y = 0;
var mouseMoveEvent = (e)=>{
if(this.throttleDate==0 || this.throttleDate+16<Date.now()){
this.withdraw()
// 获取XR和YR
var radiusX = (e.layerX-x)/2,
radiusY = (e.layerY-y)/2;
this.ctx.beginPath();
// x的圆心 = x+XR , y同上
// 角度偏移我们用不上,描边的话,我们要全部描黑,所以就0, 2 * Math.PI
this.ctx.ellipse(x+radiusX, y+radiusY, radiusX, radiusY, 0, 0, 2 * Math.PI);
this.ctx.stroke()
}
}
this.arcEvents.down = (e) => {
x = e.layerX
y = e.layerY
this.openShape = true
this.ctx.beginPath();
this.ctx.arc(x+10, y+10, 10, 0, 2 * Math.PI, false);
this.ctx.stroke()
this.canvas.addEventListener('mousemove',mouseMoveEvent)
}
this.arcEvents.up = (e) => {
this.openShape = false
this.canvas.removeEventListener('mousemove', mouseMoveEvent)
this.save()
}
this.canvas.addEventListener('mousedown', this.arcEvents.down);
this.canvas.addEventListener('mouseup', this.arcEvents.up)
}else{
// 关闭
this.toolStatus = 0
}
},
复制代码
圆的逻辑和方形差不多,唯一不同的就是生成圆的这个公式复杂一点
撤回、保存、恢复(前进)
由于我们加了图形这个工具,所以现阶段的撤回需要频繁的刷新页面,却又不改变数据,所以改良一下
withdraw(){
if(this.page > 0){
console.info('withdraw',this.openShape)
var img = new Image();
// 如果使用图形工具,就单纯撤回,不调整页数
if(!this.openShape)
this.page--
img.src = this.saveRecords[this.page-1];
console.info(this.saveRecords[this.page-1])
this.ctx.clearRect(0, 0, this.width, this.height);
img.onload = ()=>{
this.ctx.drawImage(img, 0, 0);
}
}
}
复制代码
撤回完了就是恢复(windows里面叫恢复,我们这就入乡随俗吧)
recover(){
console.info('恢复')
if(this.page<this.saveRecords.length){
// 这个变量用来告诉保存说,我恢复了,之后的页面你可以直接删除
this.useRecover = true
var img = new Image();
this.page++
img.src = this.saveRecords[this.page-1];
this.ctx.clearRect(0, 0, this.width, this.height);
img.onload = ()=>{
this.ctx.drawImage(img, 0, 0);
}
}
},
复制代码
恢复的逻辑不难,就是拿后一页的缓存图片,或者说页面
保存,竟然都改了撤回,又加了恢复,那我们的逻辑也得改改
save(){
// 如果没有撤回存档
if(this.saveRecords.length == this.page){
console.info('保存')
// 则直接保存
this.saveRecords.push(this.canvas.toDataURL())
this.page++;
}else if(this.useRecover){
console.info('恢复')
// 删除掉恢复之后的页面
for (let i = 0; i < this.saveRecords.length-this.page; i++) {
this.saveRecords.pop()
}
// 开始保存数据
// 以下俩行代码可以缩写成 this.page = this.saveRecords.length+1 ,不过写俩行比较好理解
this.page = this.saveRecords.length
this.page ++
this.saveRecords.push(this.canvas.toDataURL())
this.useRecover = false
}else{
console.info('覆盖缓存')
// 否者,则清空当前页之后的存档
for (let i = 0; i < this.saveRecords.length-this.page; i++) {
this.saveRecords.pop()
}
}
}
复制代码
总的来说改动不大,就是加了恢复要改改
二、完整代码
<template>
<div id="loon_canvas_editor">
<canvas :ref="id" :width="width" :height="height"></canvas>
<div id="toolbar">
<img :class="toolStatus==1?'select':''" @click="useBrush" src="https://wd-2019-1256239864.cos.ap-guangzhou.myqcloud.com/front/components/brush.png" alt="">
<img :class="toolStatus==2?'select':''" @click="useEraser" src="https://wd-2019-1256239864.cos.ap-guangzhou.myqcloud.com/front/components/eraser.png" alt="">
<div :class="toolStatus==3?'select shape':'shape'" @click="useSquare">
<div style="width:15px;height:15px;border: 2px solid #39f;"></div>
</div>
<div :class="toolStatus==4?'select arc':'arc'" @click="useArc">
<div style="width:15px;height:15px;border: 2px solid #39f;border-radius:50%"></div>
</div>
<div class="interval"></div>
<img @click="withdraw" src="https://wd-2019-1256239864.cos.ap-guangzhou.myqcloud.com/front/components/withdraw.png" alt="">
<img @click="recover" style="transform: rotateY(180deg);" src="https://wd-2019-1256239864.cos.ap-guangzhou.myqcloud.com/front/components/withdraw.png" alt="">
<img @click="save" src="https://wd-2019-1256239864.cos.ap-guangzhou.myqcloud.com/front/components/save.png" alt="">
</div>
</div>
</template>
<style lang="less" scoped>
#loon_canvas_editor{
width: 100%;
height: 100%;
font-size: 0;
margin: 0 auto;
canvas{
border: 1px solid #39f;
}
#toolbar{
display: flex;
width: 300px;
padding: 10px 20px;
background: #deeeff;
border: 1px solid #39f;
margin-top: -1px;
img{
width: 20px;
height: 20px;
margin-right: 10px;
}
.shape{
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
}
.arc{
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
}
.select{
border: 1px solid #222;
}
.interval{
width: 2px;
height: 20px;
background: #aaa;
margin-right: 10px;
}
}
}
</style>
<script>
import { uuid } from 'uuidv4'
export default {
name:'loonCanvasEditor',
props:[
'width',
'height'
],
data(){
return{
id:uuid(),
saveRecords:[],// 历史存档
canvas:null,
ctx:null,
toolStatus:0,
page:0, // pageIndex
throttleBrush:null, // 画笔节流
throttleDate: 0,
brushEvents:{
down:null,
up:null
},
eraserEvents:{
down:null,
up:null
},
squareEvents:{
down:null,
up:null
},
arcEvents:{
down:null,
up:null
},
openShape:false,
useRecover:false
}
},
methods:{
save(){
// 如果没有撤回存档
if(this.saveRecords.length == this.page){
console.info('保存')
// 则直接保存
this.saveRecords.push(this.canvas.toDataURL())
this.page++;
}else if(this.useRecover){
console.info('恢复')
for (let i = 0; i < this.saveRecords.length-this.page; i++) {
this.saveRecords.pop()
}
this.page = this.saveRecords.length+1
this.saveRecords.push(this.canvas.toDataURL())
this.useRecover = false
}else{
console.info('覆盖缓存')
// 否者,则清空当前页之后的存档
for (let i = 0; i < this.saveRecords.length-this.page; i++) {
this.saveRecords.pop()
}
}
},
withdraw(){
if(this.page > 0){
console.info('withdraw',this.openShape)
var img = new Image();
if(!this.openShape)
this.page--
img.src = this.saveRecords[this.page-1];
console.info(this.saveRecords[this.page-1])
this.ctx.clearRect(0, 0, this.width, this.height);
img.onload = ()=>{
this.ctx.drawImage(img, 0, 0);
}
}
},
recover(){
console.info('恢复')
if(this.page<this.saveRecords.length){
this.useRecover = true
var img = new Image();
this.page++
img.src = this.saveRecords[this.page-1];
this.ctx.clearRect(0, 0, this.width, this.height);
img.onload = ()=>{
this.ctx.drawImage(img, 0, 0);
}
}
},
// 使用画笔
useBrush(){
this.clearAllTool()
if(this.toolStatus != 1){
// 开启
this.toolStatus = 1
var mouseMoveEvent = (e)=>{
if(this.throttleDate==0 || this.throttleDate+16<Date.now()){
this.ctx.lineTo(e.layerX,e.layerY);
this.ctx.stroke();
}
}
this.brushEvents.down = (e) => {
this.ctx.beginPath();
this.ctx.moveTo(e.layerX,e.layerY);
this.canvas.addEventListener('mousemove',mouseMoveEvent)
}
this.brushEvents.up = (e) => {
this.canvas.removeEventListener('mousemove', mouseMoveEvent)
this.ctx.stroke();
this.save()
}
this.canvas.addEventListener('mousedown', this.brushEvents.down);
this.canvas.addEventListener('mouseup', this.brushEvents.up)
}else{
// 关闭
this.toolStatus = 0
}
},
// 使用橡皮
useEraser(){
this.clearAllTool()
if(this.toolStatus != 2){
this.toolStatus = 2
var mouseMoveEvent = (e)=>{
if(this.throttleDate==0 || this.throttleDate+16<Date.now()){
this.ctx.clearRect(e.layerX-5,e.layerY-5, 10,10);
}
}
this.eraserEvents.down = (e) => {
this.ctx.clearRect(e.layerX-5,e.layerY-5, 10,10);
this.canvas.addEventListener('mousemove',mouseMoveEvent)
}
this.eraserEvents.up = (e) => {
this.canvas.removeEventListener('mousemove', mouseMoveEvent)
this.save()
}
this.canvas.addEventListener('mousedown', this.eraserEvents.down);
this.canvas.addEventListener('mouseup', this.eraserEvents.up)
}else{
// 关闭
this.toolStatus = 0
}
},
// 使用框
useSquare(){
this.clearAllTool()
if(this.toolStatus != 3){
this.toolStatus = 3
var x = 0,
y = 0;
var mouseMoveEvent = (e)=>{
if(this.throttleDate==0 || this.throttleDate+16<Date.now()){
this.withdraw()
this.ctx.strokeRect(x, y, e.layerX-x,e.layerY-y);
}
}
this.squareEvents.down = (e) => {
x = e.layerX
y = e.layerY
this.openShape = true
this.ctx.strokeRect(x, y, 10,10);
this.canvas.addEventListener('mousemove',mouseMoveEvent)
}
this.squareEvents.up = (e) => {
this.openShape = false
this.canvas.removeEventListener('mousemove', mouseMoveEvent)
this.save()
}
this.canvas.addEventListener('mousedown', this.squareEvents.down);
this.canvas.addEventListener('mouseup', this.squareEvents.up)
}else{
// 关闭
this.toolStatus = 0
}
},
// 圈
useArc(){
this.clearAllTool()
if(this.toolStatus != 4){
this.toolStatus = 4
var x = 0,
y = 0;
var mouseMoveEvent = (e)=>{
if(this.throttleDate==0 || this.throttleDate+16<Date.now()){
this.withdraw()
var radiusX = (e.layerX-x)/2,
radiusY = (e.layerY-y)/2;
this.ctx.beginPath();
this.ctx.ellipse(x+radiusX, y+radiusY, radiusX, radiusY, 0, 0, 2 * Math.PI);
this.ctx.stroke()
}
}
this.arcEvents.down = (e) => {
x = e.layerX
y = e.layerY
this.openShape = true
this.ctx.beginPath();
this.ctx.arc(x+10, y+10, 10, 0, 2 * Math.PI, false);
this.ctx.stroke()
this.canvas.addEventListener('mousemove',mouseMoveEvent)
}
this.arcEvents.up = (e) => {
this.openShape = false
this.canvas.removeEventListener('mousemove', mouseMoveEvent)
this.save()
}
this.canvas.addEventListener('mousedown', this.arcEvents.down);
this.canvas.addEventListener('mouseup', this.arcEvents.up)
}else{
// 关闭
this.toolStatus = 0
}
},
clearAllTool(){
this.toolStatus = 0
console.info('清除所有工具',this.canvas.removeEventListener,this.brushEvents.down)
this.canvas.removeEventListener('mousedown',this.brushEvents.down)
this.canvas.removeEventListener('mouseup',this.brushEvents.up)
this.canvas.removeEventListener('mousedown',this.eraserEvents.down)
this.canvas.removeEventListener('mouseup',this.eraserEvents.up)
this.canvas.removeEventListener('mousedown',this.squareEvents.down)
this.canvas.removeEventListener('mouseup',this.squareEvents.up)
this.canvas.removeEventListener('mousedown',this.arcEvents.down)
this.canvas.removeEventListener('mouseup',this.arcEvents.up)
}
},
mounted(){
this.canvas = this.$refs[this.id]
this.ctx = this.canvas.getContext('2d')
this.canvas.style.width = this.width
this.canvas.style.height = this.height
this.save()
}
}
</script>
复制代码
以上就是我早上过来给你们爆肝的内容,就是不知道要审核多久,写代码去了
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END