视频展示
前端canvas实现图画工具
作者有话说
这几天学了canvas标签,在熟悉了canvas的一些属性后我决定做有个关于canvas的一个图画工具。在b站也有看到类似的功能,在看了关于这类程序后我觉得我也可以试试,顺便巩固一下自己这几天学的知识。
大概思路
代码(index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="http://at.alicdn.com/t/font_2782973_i88dmcolper.css">
<link rel="stylesheet" href="canvas画笔工具.css">
<link rel="stylesheet" href="alert.css">
</head>
<body>
<!-- 菜单功能 -->
<div class="menu">
<!-- 画笔 -->
<div class="btn iconfont icon-lujing98" id="drawPen" style="color: green;font-size: 30px;"></div>
<!-- 矩形 -->
<div class="btn iconfont icon-juxing" id="rect" style="color: skyblue;font-size: 30px;"></div>
<!-- 圆 -->
<div class="btn iconfont icon-yuan1" id="round" style="color: purple;font-size: 30px;"></div>
<!-- 线条厚度 -->
<div class="btn iconfont icon-tuopu-xiantiaocuxi" id="lineThick" style="color: orange;font-size: 30px;">
<!-- 线条 -->
<ul>
<li class="iconfont icon-hengxian- lineWidth" style="font-size: 20px;"></li>
<li class="iconfont icon-hengxian- lineWidth" style="font-size: 28px;"></li>
<li class="iconfont icon-hengxian- lineWidth" style="font-size: 38px;"></li>
<li class="iconfont icon-hengxian- lineWidth" style="font-size: 53px;"></li>
</ul>
</div>
<!-- 颜色 -->
<div class="btn iconfont icon-xuanzeyanse" id="sel_color" style="color: red;font-size: 30px;">
<!-- 颜色块 -->
<ul class="color_block_ul">
<li class="color_block" style="background-color: orchid;"></li>
<li class="color_block" style="background-color: black;"></li>
<li class="color_block" style="background-color: pink;"></li>
<li class="color_block" style="background-color: red;"></li>
<li class="color_block" style="background-color: yellow;"></li>
<li class="color_block" style="background-color: green;"></li>
<li class="color_block" style="background-color: #99d9ea;"></li>
<li class="color_block" style="background-color: #c8bfe7;"></li>
<li class="color_block" style="background-color: #b97a57;"></li>
<li class="color_block" style="background-color: #c3c3c3;"></li>
</ul>
</div>
<!-- 橡皮擦按钮 -->
<div class="btn iconfont icon-noChoiceEraser eraser_btn" style="color:#fa9693;;font-size: 30px;"></div>
<!-- 下载图片按钮 -->
<div class="btn downLoad">下载图片</div>
</div>
<!-- 画布 -->
<canvas id="mycanvas" style="z-index: 99;"></canvas>
<!-- 橡皮檫模型 -->
<div class="eraser"></div>
<!-- 下载图图片的a标签 -->
<a href="" download="download" class="downLoad_img"></a>
<script src="alert.js"></script>
<script>
// 获取canvas标签
var mycanvas = document.querySelector('#mycanvas');
mycanvas.setAttribute('width',mycanvas.offsetWidth);
mycanvas.setAttribute('height',mycanvas.offsetHeight);
var ctx = mycanvas.getContext('2d');
var eraser = document.querySelector('.eraser'); //橡皮擦
// 画布对象
var draw_board = {
type: "null",
isDraw: false,
beginX: 0, //鼠标在canvas画布上按下的x坐标
beginY: 0, //鼠标在canvas画布上按下的y坐标
dataPx: 0,
lineWidth: 3, //初始化线条的长度
color: null, //默认颜色黑色
// 画笔
penFn: function(e) {
var x = e.pageX - mycanvas.offsetLeft;
var y = e.pageY - mycanvas.offsetTop;
ctx.beginPath();
ctx.fillStyle = draw_board.color; //改变画笔的颜色·
ctx.arc(x,y,draw_board.lineWidth,0,Math.PI*2);
ctx.fill();
ctx.closePath();
},
// 画矩形
rectFn: function(e) {
var x = e.pageX - mycanvas.offsetLeft;
var y = e.pageY - mycanvas.offsetTop;
ctx.beginPath();
ctx.strokeStyle = draw_board.color;
ctx.clearRect(0,0,mycanvas.offsetWidth,mycanvas.offsetHeight); //由于画笔是用一个个小圆构成的,所以每次都要清除画板数据,不然会导致线条的成型
if(draw_board.dataPx != 0) {
ctx.putImageData(draw_board.dataPx,0,0,0,0,mycanvas.offsetWidth,mycanvas.offsetHeight); //保留画板数据
}
ctx.lineWidth = draw_board.lineWidth;
ctx.strokeRect(draw_board.beginX,draw_board.beginY,x-draw_board.beginX,y-draw_board.beginY);
ctx.closePath();
},
// 画圆
roundFn: function(e) {
var x = e.pageX - mycanvas.offsetLeft;
var y = e.pageY - mycanvas.offsetTop;
ctx.beginPath();
ctx.lineWidth = draw_board.lineWidth;
ctx.strokeStyle = draw_board.color;
ctx.clearRect(0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);
ctx.arc(draw_board.beginX,draw_board.beginY,Math.abs(y-draw_board.beginY),0,2*Math.PI);
if(draw_board.dataPx != 0) {
ctx.putImageData(draw_board.dataPx,0,0,0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);
}
ctx.stroke();
ctx.closePath();
},
// 橡皮檫
eraserFn: function(e) {
var x = e.pageX - mycanvas.offsetLeft;
var y = e.pageY - mycanvas.offsetTop;
eraser.style.left = x + "px";
eraser.style.top = y + 82 + "px";
ctx.beginPath();
ctx.clearRect(x,y,50,50);
ctx.closePath();
}
};
var btn = document.querySelectorAll('.btn');
function click_boxshowdow(tool) {
btn.forEach((item)=> {
item.classList.remove('active');
});
tool.classList.add('active');
};
// 1 选中画笔
var drawPen = document.querySelector('#drawPen');
drawPen.onclick = function() {
draw_board.type = "pen";
click_boxshowdow(this);
}
// 2 选中矩形
var rect = document.querySelector('#rect');
rect.onclick = function() {
draw_board.type = "rect";
click_boxshowdow(this);
}
// 3 选中圆形
var round = document.querySelector('#round');
round.onclick = function() {
draw_board.type = "round";
click_boxshowdow(this);
}
// 选中线段粗细
var lineThick = document.querySelector('#lineThick');
var line_lis = document.querySelectorAll('.lineWidth');
var flag_line = true;
lineThick.onclick = function() {
click_boxshowdow(this);
if(flag_line) {
line_lis.forEach(item=> {
item.style.display = "block";
});
flag_line = false;
} else {
line_lis.forEach(item=> {
item.style.display = "none";
});
flag_line = true;
}
}
// 点击改变线的粗细
for(let i = 0;i < line_lis.length;i++) {
line_lis[i].onclick = function() {
if(i == 0) {
draw_board.lineWidth = 1;
} else if(i == 1) {
draw_board.lineWidth = 2;
} else if(i == 2) {
draw_board.lineWidth = 4;
} else {
draw_board.lineWidth = 7;
}
}
}
// 选中颜色
var flag_color = true;
var color_lis = document.querySelectorAll('.color_block');
var select_color = document.querySelector('#sel_color');
select_color.addEventListener('click',function() {
click_boxshowdow(this);
if(flag_color) {
color_lis.forEach(item=> {
item.style.display = "block";
});
flag_color = false;
} else {
color_lis.forEach(item=> {
item.style.display = "none";
});
flag_color = true;
}
});
// 点击改变线条的颜色
for(let j = 0;j < color_lis.length;j++) {
color_lis[j].onclick = function() {
switch(j) {
case 0:
draw_board.color = "orchid";
break;
case 1:
draw_board.color = "black";
break;
case 2:
draw_board.color = "pink";
break;
case 3:
draw_board.color = "red";
break;
case 4:
draw_board.color = "yellow";
break;
case 5:
draw_board.color = "green";
break;
case 6:
draw_board.color = "#99d9ea";
break;
case 7:
draw_board.color = "#c8bfe7";
break;
case 8:
draw_board.color = "#b97a57";
break;
case 9:
draw_board.color = "#c3c3c3";
break;
}
}
}
// 选中橡皮擦
var eraser_exit = true;
var eraser_btn = document.querySelector('.eraser_btn');
eraser_btn.onclick = function() {
click_boxshowdow(this);
if(eraser_exit) {
eraser.style.display = "block";
eraser_exit = false;
} else {
eraser.style.display = "none";
eraser_exit = true;
}
draw_board.type = "eraser";
}
// 选中下载图片
var num = -1;
var downLoad = document.querySelector('.downLoad');
downLoad.onclick = function() {
click_boxshowdow(this);
var url = mycanvas.toDataURL();
var p = {
content: '<img src= ' + '"' + url + '"' + '>',
title: '点击确定下载图片'
}
PopupWindow(p,++num,url);
}
// 在画布中鼠标按下事件
mycanvas.onmousedown = function(e) {
if(!eraser_exit) {
eraser.style.display = "block";
}
draw_board.isDraw = true;
draw_board.beginX = e.pageX - mycanvas.offsetLeft;
draw_board.beginY= e.pageY - mycanvas.offsetTop;
}
// 在画布中鼠标抬起时间
mycanvas.onmouseup = function(e) {
draw_board.isDraw = false;
draw_board.dataPx = ctx.getImageData(0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);
}
// 在画布中鼠标移动事件
mycanvas.onmousemove = function(e) {
if(draw_board.isDraw) {
if(draw_board.type != 'null') {
var str = draw_board.type + "Fn";
draw_board[str](e);
}
}
}
</script>
</body>
</html>
canvas画笔工具.css
* {
padding: 0;
margin: 0;
}
.lineWidth {
list-style: none;
border-radius: 15px;
border: 1px solid pink;
height: 37px;
line-height: 37px;
display: none;
}
.lineWidth:hover {
background-color: skyblue;
}
.color_block {
display: none;
list-style: none;
margin-top: 5px;
height: 25px;
line-height: 25px;
width: 110px;
background-color: orange;
}
.color_block:hover {
width: 130px;
}
.color_block div {
display: none;
float: left;
margin-right: 7px;
width: 30px;
height: 30px;
background-color: skyblue;
}
body {
position: relative;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.menu {
z-index: 999;
display: flex;
justify-content: space-around;
align-items: center;
width: 100%;
height: 100px;
}
.btn {
border: 3px solid pink;
width: 120px;
height: 53px;
border-radius: 15px;
line-height: 53px;
text-align: center;
cursor: pointer;
display: flex;
flex-direction: column;
}
#mycanvas {
height: 100vh;
border: 3px solid skyblue;
}
.active {
box-shadow: 0 0 20px 3px gold;
border: 3px solid gold;
}
.eraser {
position: absolute;
display: none;
width: 50px;
height: 50px;
background-color: pink;
opacity: 0.5;
left: 1800px;
}
alert.js(点击下载画好的图片时的弹窗)
function PopupWindow(args,num,url) {
if(num >=1) {
var div_box = document.querySelector('.alert');
var body = document.querySelector('body');
body.removeChild(div_box);
}
var div = document.createElement('div');
var body = document.querySelector('body');
mycanvas.style.backgroundColor = "#333";
div.className = "alert";
div.innerHTML = `
<div class="title">` + args.title + `</div>
<div class="main">` + args.content + `</div>
<div class="bottom">
<button class = "cancel">取消</button>
<button class = "right">确定</button>
</div>
`;
body.appendChild(div);
var right = document.querySelector('.right');
var cancel = document.querySelector('.cancel');
var div_box = document.querySelector('.alert');
right.onclick = function() {
var downLoad_img = document.querySelector('.downLoad_img');
downLoad_img.setAttribute("href",url);
mycanvas.style.backgroundColor = "white";
downLoad_img.click();
div_box.style.display = "none";
}
cancel.onclick = function() {
div_box.style.display = "none";
mycanvas.style.backgroundColor = "white";
}
};
alert.css
.alert {
position: absolute;
z-index: 99999;
left: 33%;
top: 27%;
width: 450px;
height: 300px;
border: 1px solid pink;
background-color: white;
}
.title {
width: 100%;
height: 60px;
text-align: center;
line-height: 60px;
background-color: #ccc;
color: white;
}
.main {
width: 100%;
height: 60%;
}
.main img {
width: 100%;
height: 100%;
}
.bottom {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
width: 100%;
height: 20%;
line-height: 20%;
border-top: 1px solid pink;
}
/* 以下为下载图片按钮样式 */
/* 确定按钮特效 */
.right,.cancel {
position: relative;
width: 100px;
height: 50px;
border: 1px solid white;
transition: all 1s ease-in-out;
background-color: white;
}
.right:hover {
background-color: pink;
color: white;
transition-delay: 0.4s;
}
.right::before,.right::after {
content: '';
position: absolute;
width: 15px;
height: 15px;
border: 2px pink solid;
transition: width 0.2s ease-in-out 0.2s;
}
.right::before {
left: 0;
top: 0;
border-right: 0;
border-bottom: 0;
}
.right::after {
right: 0;
bottom: 0;
border-left: 0;
border-top: 0;
}
.right:hover::after,
.right:hover::before {
width: 96px;
height: 46px;
}
/* 取消按钮特效 */
.cancel::before,.cancel::after {
content: '';
position: absolute;
width: 15px;
height: 15px;
border: 2px orange solid;
transition: width 0.2s ease-in-out 0.2s;
}
.cancel::before {
left: 0;
top: 0;
border-right: 0;
border-bottom: 0;
}
.cancel::after {
right: 0;
bottom: 0;
border-left: 0;
border-top: 0;
}
.cancel:hover {
background-color: orange;
color: white;
transition-delay: 0.4s;
}
.cancel:hover::after,
.cancel:hover::before {
width: 96px;
height: 46px;
}