網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
canvas實(shí)現(xiàn)畫板功能
-
canvas實(shí)現(xiàn)畫板功能
- Setp1構(gòu)建網(wǎng)頁(yè)基本樣式
- Step2構(gòu)造實(shí)現(xiàn)畫板各個(gè)功能的js代碼
- Step3加載js文件
需求分析
1.具有基本的鉛筆功能
2.即時(shí)直線繪制
3.即時(shí)繪制矩形
4.即時(shí)圓形
5.即時(shí)橡皮擦
7.插入圖片
8.把畫板保存為圖片并下載 //此處還沒(méi)做好,畫板底色是黑色的
9.選擇顏色
10.選擇線條粗細(xì)
Setp1:構(gòu)建網(wǎng)頁(yè)基本樣式
html代碼
<div id="select">
<button id="pen">鉛筆button>
<button id="line">直線button>
<button id="rect">矩形button>
<button id="arc">圓形button>
<button id="robber">橡皮檫button>
<button id="img">圖片button>
<button id="save">保存button>
<input type="file" id="file" name="img" style="display: none"/>
<input type="color" id="color"/>
<input type="number" id="lineWidth"/>
div>
<canvas id="penal" width="800" height="800">canvas>
css代碼
/*只有一句,用來(lái)初始化畫板顏色*/
#penal {
width: 800px;
height: 800px;
background-color: #ccc;
}
Step2:構(gòu)造實(shí)現(xiàn)畫板各個(gè)功能的js代碼
1.構(gòu)造
Draw()
類,并初始化必要的參數(shù)
var Draw = function(){
this.type = 'pen'; //選項(xiàng)類型,默認(rèn)為鉛筆
this.penal = document.getElementById('penal');
this.pen = this.penal.getContext('2d');
this.isDraw = false; //繪畫開(kāi)關(guān)
this.color = document.getElementById('color');
this.lineWidth = document.getElementById('lineWidth');
this.select = document.getElementById('select'); //選擇面板
this.img = new Image();//用于動(dòng)態(tài)繪制直線,矩形,圓形
};
2.這里只需要構(gòu)造一個(gè)初始化函數(shù)
init()
初始化函數(shù)內(nèi)部需要用到的變量
Draw.prototype.init = function(){
var self = this;
var originX = null;
var originY = null;
}
先綁定選擇操作
this.select.addEventListener('click',function(event){
if(event.target.id == 'pen'){
self.type = 'pen';
}else if(event.target.id == 'line'){
self.type = 'line';
}else if(event.target.id == 'rect'){
self.type = 'rect';
}else if(event.target.id == 'arc'){
self.type = 'arc';
}else if(event.target.id == 'robber'){
self.type = 'robber';
}else if(event.target.id == 'img'){
document.getElementById('file').click(); //默認(rèn)觸發(fā)選擇文件操作
document.getElementById('file').onchange = function(e){
var reader = new FileReader(); //這是H5新增加的讀取文件函數(shù)
reader.readAsDataURL(e.target.files[0]);
reader.onload = function(ent){ //文件讀取完畢后觸發(fā)操作
var img = new Image();
img.src = ent.target.result; //讀取的結(jié)果默認(rèn)存放在result上
self.pen.drawImage(img,0,0); //把圖片直接畫在畫布上
}
}
}
else if(event.target.id == 'save'){
var a = document.createElement('a');
a.href = self.penal.toDataURL('image/png'); //把畫布轉(zhuǎn)化為base64
a.download = 'image.jpeg';
a.id = 'download';
a.innerHTML = 'download';
document.body.appendChild(a);
document.getElementById('download').style.display = 'none';
document.getElementById('download').click(); //默認(rèn)出發(fā)下載操作
}
},false);
可以知道當(dāng)繪畫時(shí),
mousedown
事件觸發(fā)時(shí),需要把this.isDraw = true
,同時(shí)記錄鼠標(biāo)所在坐標(biāo),獲取選擇的color
和linewidth
,并開(kāi)啟繪畫路徑
this.penal.addEventListener('mousedown',function(event){
self.isDraw = true;
originX = event.clientX - self.penal.offsetLeft; //原點(diǎn)x坐標(biāo)
originY = event.clientY - self.penal.offsetTop; //原點(diǎn)y坐標(biāo)
self.pen.moveTo(originX, originY);
self.pen.strokeStyle = self.color.value;
self.pen.lineWidth = self.lineWidth.value;
self.pen.beginPath();
},false);
然后當(dāng)觸發(fā)
mouseup
事件時(shí),可知需要結(jié)束繪畫,若鼠標(biāo)離開(kāi)畫布,即mouseleave
時(shí),也需要結(jié)束繪畫,這部分很簡(jiǎn)單只需把this.isDraw = false
和關(guān)閉繪畫路徑
this.penal.addEventListener('mouseleave', function () {
if(self.isDraw){
self.pen.closePath();
self.isDraw = false;
}
},false);
this.penal.addEventListener('mouseup', function (event) {
if(self.isDraw){
self.pen.closePath();
self.isDraw = false;
}
},false);
接下來(lái)就是最難的部分的,當(dāng)
mouseover
時(shí),需要即時(shí)繪制
先實(shí)現(xiàn)鉛筆功能
this.penal.addEventListener('mousemove',function(event){
//只有可繪畫時(shí)才可畫
if(self.isDraw){
var x = event.clientX - self.penal.offsetLeft; //移動(dòng)過(guò)程中的x坐標(biāo)
var y = event.clientY - self.penal.offsetTop; //移動(dòng)過(guò)程中的y坐標(biāo)
if(self.type == 'pen'){
self.pen.lineTo(x,y);
self.pen.stroke();
}
}
},false);
接下來(lái)實(shí)現(xiàn)橡皮擦功能,實(shí)現(xiàn)方法是把繪畫線條加粗,并顏色默認(rèn)選擇畫布底色
if(self.type == 'robber'){
self.pen.strokeStyle = '#ccc';
self.pen.clearRect(x-10,y-10,20,20);
}
接下來(lái)實(shí)現(xiàn)繪制直線,矩形和圓形的方法其實(shí)大同小異,然后為了能讓我們畫矩形和圓形能在所有方向都能畫,我們?cè)黾恿?code>newOriginX和
newOriginY
兩個(gè)變量
var newOriginX = originX,newOriginY = originY;
if(self.type == 'line'){
self.pen.moveTo(originX,originY);
self.pen.lineTo(x,y);
self.pen.stroke();
}else if(self.type == 'rect'){
if(x < originX){
newOriginX = x;
}
if(y < originY){
newOriginY = y;
}
self.pen.rect(newOriginX,newOriginY,Math.abs(x-originX),Math.abs(y-originY));
self.pen.stroke();
}else if(self.type == 'arc'){
if(x < originX){
newOriginX = x;
}
if(y < originY){
newOriginY = y;
}
var r = Math.sqrt(Math.abs(x-originX) * Math.abs(x-originX) + Math.abs(y-originY) * Math.abs(y-originY))
self.pen.arc(Math.abs(x-originX)+newOriginX, Math.abs(y-originY)+newOriginY , r, 0, 2*Math.PI);
self.pen.fillStyle = self.color.value;
self.pen.fill();
}
question:
此時(shí)我們發(fā)現(xiàn)畫的直線,矩形和圓形都會(huì)在畫的時(shí)候留下移動(dòng)的痕跡,這不是我們希望的結(jié)果,所以解決方法是:
在mousedown
時(shí),把當(dāng)前畫布內(nèi)容保存為圖片,并用初始化時(shí)一直沒(méi)有使用過(guò)的this.img
來(lái)保存,然后每次畫直線等的時(shí)候先把畫布全部清空,然后在把this.img
畫到畫布上
把原來(lái)的mousedown
事件添加一句代碼
this.penal.addEventListener('mousedown',function(event){
self.isDraw = true;
//增加一句代碼
self.img.src = self.penal.toDataURL('image/png');
originX = event.clientX - self.penal.offsetLeft; //原點(diǎn)x坐標(biāo)
originY = event.clientY - self.penal.offsetTop; //原點(diǎn)y坐標(biāo)
self.pen.moveTo(originX, originY);
self.pen.strokeStyle = self.color.value;
self.pen.lineWidth = self.lineWidth.value;
self.pen.beginPath();
},false);
把
mouseover
事件的代碼稍作更改
if(self.type == 'line'){
self.pen.clearRect(0,0,800,800);//增加代碼
self.pen.drawImage(self.img, 0, 0);//增加代碼
self.pen.beginPath();//增加代碼
self.pen.moveTo(originX,originY);
self.pen.lineTo(x,y);
self.pen.stroke();
self.pen.closePath();//增加代碼
}else if(self.type == 'rect'){
self.pen.clearRect(0,0,800,800);//增加代碼
self.pen.drawImage(self.img, 0, 0);//增加代碼
self.pen.beginPath();//增加代碼
if(x < originX){
newOriginX = x;
}
if(y < originY){
newOriginY = y;
}
self.pen.rect(newOriginX,newOriginY,Math.abs(x-originX),Math.abs(y-originY));
self.pen.stroke();
self.pen.closePath();//增加代碼
}else if(self.type == 'arc'){
self.pen.clearRect(0,0,800,800);//增加代碼
self.pen.drawImage(self.img, 0, 0);//增加代碼
self.pen.beginPath();//增加代碼
if(x < originX){
newOriginX = x;
}
if(y < originY){
newOriginY = y;
}
var r = Math.sqrt(Math.abs(x-originX) * Math.abs(x-originX) + Math.abs(y-originY) * Math.abs(y-originY))
self.pen.arc(Math.abs(x-originX)+newOriginX, Math.abs(y-originY)+newOriginY , r, 0, 2*Math.PI);
self.pen.fillStyle = self.color.value;
self.pen.fill();
self.pen.closePath();//增加代碼
}
Step3:加載js文件
<script src="draw.js">script>
<script>
window.onload = function (){
var draw = new Draw();
draw.init();
};
script>
最后簡(jiǎn)單的畫板功能就是實(shí)現(xiàn)了,如有不足之處請(qǐng)指出
demo地址:https://github.com/1364137942/canvas-draw-panel
原文鏈接:https://blog.csdn.net/ali1995/article/details/52734253
相關(guān)推薦
- 2023-02-07 Hive數(shù)據(jù)去重的兩種方式?(distinct和group?by)_數(shù)據(jù)庫(kù)其它
- 2022-11-23 詳解React?Native中如何使用自定義的引用路徑_React
- 2022-10-19 Python?Pandas?修改表格數(shù)據(jù)類型?DataFrame?列的順序案例_python
- 2022-11-25 命令行下執(zhí)行TypeScript文件的三種方法_基礎(chǔ)知識(shí)
- 2022-12-29 Python?PyQt5學(xué)習(xí)之樣式設(shè)置詳解_python
- 2022-06-12 詳解Go語(yǔ)言中的數(shù)據(jù)類型及類型轉(zhuǎn)換_Golang
- 2022-02-15 多標(biāo)簽界面:動(dòng)態(tài)組件 & 異步組件
- 2022-10-13 C++?auto自動(dòng)類型推導(dǎo)規(guī)則和使用詳解_C 語(yǔ)言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支