This article mainly introduces:
Name: Smart Drawing Board
Technology stack: HTML5, CSS3, JavaScript, mobile
Function description:
Project address preview address
Preview
PC preview:
Mobile preview:
After reading the preview above and experiencing the Smart Drawing Pad , I think it’s okay. Remember to give it a thumbs up. Regardless of whether you are very excited or not, I am quite excited anyway. After all, I am very proud to have achieved the project results. I have said it. A bunch of nonsense, now you can start typing code to achieve the effect you want! ! !
Note: The following project effects are mainly related to JavaScript. The following is only the code that provides implementation ideas , not the entire code .
3. Achieve project results step by step(1) Analysis page
Through the use case diagram , we know what functions users can use to enter our website?
What users can do:
(2) HTML layout
When I wrote html, I introduced css files and js files
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <meta name=viewport content=width=device-width, initial-scale=1.0> <meta http-equiv=X-UA -Compatible content=ie=edge> <title>Smart Drawing Pad</title> <link rel=shortcut icon href=./image/favicon.png type=image/x-icon> <link rel=stylesheet href=./css/style.css></head><body> <canvas id=canvas></canvas> <div class=bg-btn></ div> <div class=color-group id=bgGroup> <h3>Select background color:</h3> <ul class=clearfix> <li class=bgcolor-item style=background-color: blue;></li> <li class=bgcolor-item style=background-color: black;></li> <li class=bgcolor-item style=background-color: #FF3333;></li> <li class=bgcolor-item style=background-color: #0066FF;></li> <li class=bgcolor-item style=background-color: #FFFF33;></li> <li class=bgcolor-item style=background-color: #33CC66;></li> <li class=bgcolor-item style=background-color: gray;></li> <li class=bgcolor-item style=background- color: #F34334;></li> <li class=bgcolor-item style=background-color: #fff;box-shadow: 0 1px 2px 0 rgba(32,33,36,0.28);></li> <li class=bgcolor-item style=background-color: #9B27AC;></li> <li class=bgcolor-item style=background-color: #4CB050;></li> <li class=bgcolor-item style=background-color: #029688;></li> </ul> <i class=closeBtn></i> </div> <div class=tools> <div class=container> <button class=save id=save <button class=brush active id=brush <button class=eraser id=eraser < button class=clear id=clear <button class=undo id=undo <button class=redo id=redo </div> </div> <div class=pen-detail id=penDetail> <i class=closeBtn></i> <p>Pen size</p> <span class=circle-box><i id=thickness></i></span> <input type=range id=range1 min=1 max=10 value=1> <p>Pen color</p> <ul class=pen-color clearfix> <li class=color-item active style=background-color: black;></ li> <li class=color-item style=background-color: #FF3333;></li> <li class=color-item style=background-color: #99CC00;></li> <li class=color-item style=background -color: #0066FF;></li> <li class=color-item style=background-color: #FFFF33;></li> <li class=color-item style=background-color: #33CC66;></li> </ul> <p>Opacity</p> <i class=showOpacity></i> <input type=range id=range2 min=1 max=10 value=1> < /div> <script src=./js/main.js></script></body></html>
(3) Use CSS to beautify the interface
The css code can beautify the interface according to personal habits, so I won’t write the css code here. You can directly look at the project code or review the elements from the developer tools. If you have any questions, you can chat with me privately. I don’t think it’s a big problem.
(4) Use JS to implement specific functions of the project
1. Preparation
First, prepare a container, which is a drawing board. The container has been written in the previous HTML. This is pure nonsense.
<canvas id=canvas></canvas>
Then initialize js
let canvas = document.getElementById('canvas');let context = canvas.getContext('2d'); I plan to make the artboard full screen, so next I will set the width and height of canvas
let pageWidth = document.documentElement.clientWidth;let pageHeight = document.documentElement.clientHeight;canvas.width = pageWidth;canvas.height = pageHeight;
Since some IEs do not support canvas , if we want to be compatible with IE, we can create a canvas , then initialize it with excanvas , and add exCanvas.js for IE. We explicitly do not consider IE here.
But when I change the browser window on my computer, the drawing board does not scale adaptively. Solution:
// Remember to execute the autoSetSize function function autoSetSize(){ canvasSetSize(); // When executing this function, the width and height of the canvas will be set first function canvasSetSize(){ let pageWidth = document.documentElement.clientWidth; let pageHeight = document.documentElement.clientHeight; canvas.width = pageWidth; canvas.height = pageHeight; } // After the window size changes, the resize event will be triggered to reset the width and height of the canvas window.onresize = function(){ canvasSetSize(); }}2. Realize the function of drawing
Implementation idea: listen to mouse events and use drawLine() method to draw the recorded data.
painting = false .mousedown ), set painting to true , indicating that painting is being done and the mouse is not released. Record the mouse clicks.mousemove ). If the mouse moves too fast, the browser cannot keep up with the drawing speed, and gaps will appear between points, so we need to connect the drawn points with lines ( lineTo() ).mouseup ), set painting to false . Note: This method drawCircle actually does not need to be written. This is just to let everyone understand where to start clicking?
function listenToUser() { // Define a variable to initialize the brush state let painting = false; // Record the last position of the brush let lastPoint = {x: undefined, y: undefined}; // Mouse press event canvas.onmousedown = function (e){ painting = true; let x = e.clientX; let y = e.clientY; lastPoint = {'x':x,'y':y}; drawCircle(x,y,5); } //Mouse move event canvas.onmousemove = function(e){ if(painting){ let x = e.clientX; let y = e.clientY; let newPoint = {'x' :x,'y':y}; drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y); lastPoint = newPoint; } } // Mouse release event canvas.onmouseup = function(){ painting = false; }}// Draw point function function drawCircle(x,y,radius){ // Create a new path. After generation, the graphics drawing command is pointed to the path Generate path. context.beginPath(); // Draw an arc (circle) with (x, y) as the center and radius as the radius, // starting from startAngle and ending at endAngle, in the direction given by anticlockwise (the default is clockwise ) to generate. context.arc(x,y,radius,0,Math.PI*2); // Generate a solid graphic by filling the content area of the path context.fill(); // After closing the path, the graphic drawing command is redirected to the context. middle. context.closePath();}function drawLine(x1,y1,x2,y2){ //Set the line width context.lineWidth = 10; //Set the line end style. context.lineCap = round; // Set the style of the joint between lines context.lineJoin = round; // moveTo(x,y) moves the stroke to the specified coordinates x and y context.moveTo(x1,y1 ); // lineTo(x, y) draws a straight line from the current position to the specified x and y position context.lineTo(x2,y2); // Draw the graphic outline through lines context.stroke(); context.closePath();}3. Implement the eraser function
Implementation ideas:
eraserEnabled = false .click event, click the eraser, change the eraser state, eraserEnabled = true , and switch the class to achieve the activated effect.eraserEnabled is true , move the mouse and use context.clearRect() to implement eraser. But I found that in the canvas API, the clearRect method can clear pixels, but the clearRect method clears the rectangular area. After all, most people’s erasers are accustomed to being round, so the powerful function of the clipping area is introduced. , which is the clip method. The following code uses context.clearRect() to implement eraser. Please see the step-by-step section to learn how to better implement rubber sassafras.
let eraser = document.getElementById(eraser);let eraserEnabled = false;// Remember to execute the listenToUser function function listenToUser() { // ... means the previously written code is omitted // ... // Mouse press Next event canvas.onmousedown = function(e){ // ... if(eraserEnabled){//To use eraser context.clearRect(x-5,y-5,10,10) }else{ lastPoint = {'x':x,'y':y} } } // Mouse move event canvas.onmousemove = function(e){ let x = e.clientX; let y = e.clientY; if( !painting){return} if(eraserEnabled){ context.clearRect(x-5,y-5,10,10); }else{ var newPoint = {'x':x,'y':y}; drawLine(lastPoint.x, lastPoint.y,newPoint.x, newPoint.y); lastPoint = newPoint; } } // ...}// Click the eraser eraser.onclick = function(){ eraserEnabled = true; eraser.classList.add('active'); brush.classList.remove('active');}4. Implement screen clearing function
Implementation ideas:
Get the element node.
Click the Clear button to clear the canvas.
let reSetCanvas = document.getElementById(clear);//Realize screen clearing reSetCanvas.onclick = function(){ ctx.clearRect(0,0,canvas.width,canvas.height); setCanvasBg('white');}// Reset canvas background color function setCanvasBg(color) { ctx.fillStyle = color; ctx.fillRect(0, 0, canvas.width, canvas.height);}5. Implement the function of saving as a picture
Implementation ideas:
let save = document.getElementById(save); // Download image save.onclick = function(){ let imgUrl = canvas.toDataURL('image/png'); let saveA = document.createElement('a'); document. body.appendChild(saveA); saveA.href = imgUrl; saveA.download = 'mypic'+(new Date).getTime(); saveA.target = '_blank'; saveA.click();}6. Implement the function of changing the background color
Implementation ideas:
let selectBg = document.querySelector('.bg-btn');let bgGroup = document.querySelector('.color-group');let bgcolorBtn = document.querySelectorAll('.bgcolor-item');let penDetail = document. getElementById(penDetail);let activeBgColor = '#fff';//implemented switching background color for (let i = 0; i < bgcolorBtn.length; i++) { bgcolorBtn[i].onclick = function (e) { // Stop bubbling e.stopPropagation(); for (let i = 0; i < bgcolorBtn.length ; i++) { bgcolorBtn[i].classList.remove(active); this.classList.add(active); activeBgColor = this.style.backgroundColor; setCanvasBg(activeBgColor); } }}document.onclick = function(){ bgGroup.classList.remove('active');}selectBg.onclick = function(e){ bgGroup.classList.add(' active'); e.stopPropagation();}7. Implement the function of changing the thickness of the brush
Implementation ideas:
let range1 = document.getElementById('range1');let lWidth = 2;let ifPop = false;range1.onchange = function(){ console.log(range1.value); console.log(typeof range1.value) thickness. style.transform = 'scale('+ (parseInt(range1.value)) +')'; console.log(thickness.style.transform ) lWidth = parseInt(range1.value*2);}// Line drawing function function drawLine(x1,y1,x2,y2){ // ... context.lineWidth = lWidth; // ...}// Click the brush brush. onclick = function(){ eraserEnabled = false; brush.classList.add('active'); eraser.classList.remove('active'); if(!ifPop){ // Pop-up box console.log('pop') penDetail.classList.add('active'); }else{ penDetail.classList.remove('active'); } ifPop = !ifPop;}8. Implement the function of changing the brush color
The implementation idea is similar to the idea of changing the background color of the drawing board .
let aColorBtn = document.getElementsByClassName(color-item);getColor();function getColor(){ for (let i = 0; i < aColorBtn.length; i++) { aColorBtn[i].onclick = function () { for ( let i = 0; i < aColorBtn.length; i++) { aColorBtn[i].classList.remove(active); this.classList.add(active); activeColor = this.style.backgroundColor; ctx.fillStyle = activeColor; ctx.strokeStyle = activeColor; } } }}9. Implement the functions of undo and redo changes
Implementation ideas:
canvasHistory array every time a drawing operation is completed (use toDataURL() method of canvas to generate a snapshot, which generates a base64 image);canvasHistory array using drawImage() method of canvas; let undo = document.getElementById(undo);let redo = document.getElementById(redo);// ...canvas.onmouseup = function(){ painting = false; canvasDraw();}let canvasHistory = [];let step = -1; // Drawing method function canvasDraw(){ step++; if(step < canvasHistory.length){ canvasHistory.length = step; // Truncate array} // Add a new draw to the history canvasHistory.push(canvas.toDataURL());}//Undo method function canvasUndo(){ if(step > 0){ step--; // ctx.clearRect(0,0,canvas .width,canvas.height); let canvasPic = new Image(); canvasPic.src = canvasHistory[step]; canvasPic.onload = function () { ctx.drawImage(canvasPic, 0, 0); } undo.classList.add('active'); }else{ undo.classList.remove('active'); alert('Cannot continue to undo'); }} // Redo method function canvasRedo(){ if(step < canvasHistory.length - 1){ step++; let canvasPic = new Image(); canvasPic.src = canvasHistory[step]; canvasPic.onload = function () { // ctx.clearRect(0,0,canvas.width,canvas.height); ctx.drawImage(canvasPic, 0, 0); } redo.classList.add( 'active'); }else { redo.classList.remove('active') alert('Already the latest record'); }}undo.onclick = function(){ canvasUndo();}redo.onclick = function(){ canvasRedo();}10. Compatible with mobile terminals
Implementation ideas:
true , the touch event is used; false , mouse event is used // ...if (document.body.ontouchstart !== undefined) { // Use touch event anvas.ontouchstart = function (e) { // Start touching} canvas.ontouchmove = function (e) { // Start sliding } canvas.ontouchend = function () { // End of sliding }}else{ // Use mouse event // ... } // ... 4. Trampling on pitfalls Problem 1: When you change the browser window on your computer, the drawing board will not adapt.Solution:
In onresize response event processing, the page size parameters obtained are the changed parameters.
When the window size changes, reset the width and height of the canvas. To put it simply, after the window changes, reassign canvas.width and canvas.height.
// Remember to execute the autoSetSize function function autoSetSize(){ canvasSetSize(); // When executing this function, the width and height of the canvas will be set first function canvasSetSize(){ let pageWidth = document.documentElement.clientWidth; let pageHeight = document.documentElement.clientHeight; canvas.width = pageWidth; canvas.height = pageHeight; } // After the window size changes, the resize event will be triggered to reset the width and height of the canvas window.onresize = function(){ canvasSetSize(); }} Question 2: When the width of the drawn line is relatively small, it is fine, but once it is thicker, problems will occur.Solution: Take a look at the documentation and figure out the method. You just need to simply modify the code for drawing lines .
// Line drawing function function drawLine(x1,y1,x2,y2){ context.beginPath(); context.lineWidth = lWidth; //-----Add----- // Set the line end style. context.lineCap = round; // Set the style of the junction between lines context.lineJoin = round; //-----Join----- context.moveTo(x1,y1); context.lineTo( x2,y2); context.stroke(); context.closePath();} Question 3: How to achieve a round rubber sassafras?Solution:
In the canvas API, the clearRect method can clear pixels, but the clearRect method clears a rectangular area. After all, most people's erasers are accustomed to being round, so the powerful function of the clipping area is introduced, that is clip method. Usage is very simple:
ctx.save()ctx.beginPath()ctx.arc(x2,y2,a,0,2*Math.PI);ctx.clip()ctx.clearRect(0,0,canvas.width,canvas.height) ;ctx.restore();
The above code realizes the erasure of a circular area, that is, first implements a circular path, then uses this path as the clipping area, and then clears the pixels. One thing to note is that you need to save the drawing environment first, and reset the drawing environment after clearing the pixels. If you do not reset, future drawings will be limited to that clipping area.
Question 4: How to be compatible with mobile terminals?1.Add meta tag
Because the browser will initially scale the page when it is displayed on the mobile phone, we can set the meta viewport attribute in the meta tag to tell the browser not to scale the page. Page width = user device screen width
<meta name=viewport content=width=device-width,initial-scale=1,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0/>/*Page width=Mobile width:width=device-width User cannot scale : user-scalable=no scaling: initial-scale=1 maximum scaling: maximum-scale=1.0 minimum scaling: minimum-scale=1.0*/
2. Almost all touch events are used on the mobile side, which is different from the PC side.
Since the mobile side uses touch events, the H5 attributes touchstart/touchmove/touchend are used. However, the PC side only supports mouse events, so feature detection is required.
In the touch event, the coordinates are obtained through .touches[0].clientX and .touches[0].clientY , which should be distinguished from the mouse event.
Well, it’s not a big problem. It’s just that I missed writing context.beginPath(); and spent some time solving the bug on it. It reminds me that there are tens of millions of lines of code, and the first line of comments is not standardized; the programming is not standardized, and my colleague has two lines. Tears, it’s better to operate according to the documented operating specifications, it smells so good! ! !
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.