이 글에서는 주로 다음을 소개합니다.
이름: 스마트 드로잉 보드
기술 스택: HTML5, CSS3, JavaScript, 모바일
기능 설명:
프로젝트 주소 미리보기 주소
시사
PC 미리보기:
모바일 미리보기:
위의 미리보기를 읽고 Smart Drawing Pad를 경험해 보면 괜찮다고 생각합니다. 매우 기대되든 아니든 어쨌든 매우 기쁘게 생각합니다. 말도 안 되는 소리지만 이제 원하는 효과를 얻기 위해 코드를 입력할 수 있습니다! ! !
참고: 다음 프로젝트 효과는 주로 JavaScript와 관련이 있습니다. 다음은 전체 코드가 아닌 구현 아이디어를 제공하는 코드 입니다.
3. 단계별로 프로젝트 성과 달성(1) 분석 페이지
사용 사례 다이어그램을 통해 사용자가 웹 사이트에 접속하기 위해 어떤 기능을 사용할 수 있는지 알 수 있습니까?
사용자가 할 수 있는 작업:
(2) HTML 레이아웃
HTML을 작성할 때 CSS 파일과 js 파일을 소개했습니다.
<!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 -호환되는 콘텐츠=ie=edge> <title>스마트 드로잉 패드</title> <link rel=단축 아이콘 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>배경색 선택:</h3> <ul class=clearfix> <li class=bgcolor-item style=배경-색상: blue;></li> <li class=bgcolor-item 스타일=배경-색상: 검정;></li> <li class=bgcolor-item 스타일=배경-색상: #FF3333;></li> <li class=bgcolor-item 스타일=배경색: #0066FF;></li> <li class=bgcolor-item 스타일=배경색: #FFFF33;></li> <li class=bgcolor-item 스타일=배경색: #33CC66;></li> <li class=bgcolor-item 스타일=배경색: 회색;></li> <li class=bgcolor-item 스타일=배경- 색상: #F34334;></li> <li class=bgcolor-item 스타일=배경-색상: #fff;상자 그림자: 0 1px 2px 0 rgba(32,33,36,0.28);></li> <li class=bgcolor-item 스타일=배경-색상: #9B27AC;></li> <li class=bgcolor-item 스타일=배경-색상: #4CB050;></li> <li class=bgcolor-item 스타일=배경색: #029688;></li> </ul> <i class=closeBtn></i> </div> <div class=tools> <div class=container> <button class=save id=save <button class=brush 활성 id=brush <button class=eraser id=eraser < 버튼 클래스=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>펜 크기</p> <span class=circle-box><i id=thickness></i></span> <input type=range id=range1 min=1 max=10 value=1> <p>펜 색상</p> <ul class=pen-colorclearfix> <li class=color-item active style=Background-color: black;></ 리> <리 class=color-item 스타일=배경-색상: #FF3333;></li> <li class=color-item 스타일=배경-색상: #99CC00;></li> <li class=color-item 스타일=배경 -색상: #0066FF;></li> <li class=color-item 스타일=배경색: #FFFF33;></li> <li class=color-item 스타일=배경-색상: #33CC66;></li> </ul> <p>불투명도</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) CSS를 사용하여 인터페이스를 아름답게 만듭니다.
CSS 코드는 개인적인 습관에 따라 인터페이스를 아름답게 할 수 있으므로 여기서는 CSS 코드를 작성하지 않겠습니다. 프로젝트 코드를 직접 보거나 개발자 도구에서 요소를 검토할 수 있습니다. 궁금한 점이 있으면 개인적으로 채팅해도 됩니다. 큰 문제는 아닌 것 같습니다.
(4) JS를 사용하여 프로젝트의 특정 기능을 구현합니다.
1. 준비
먼저 드로잉 보드인 컨테이너를 준비합니다. 컨테이너는 이전 HTML에서 작성되었습니다.
<캔버스 id=캔버스></canvas>
그런 다음 js를 초기화하십시오.
let canvas = document.getElementById('canvas');let context = canvas.getContext('2d'); 아트보드를 전체 화면으로 만들 예정이므로 다음에는 canvas
let pageWidth = document.documentElement.clientWidth;let pageHeight = document.documentElement.clientHeight;canvas.width = pageWidth;canvas.height = pageHeight;
일부 IE는 canvas 지원하지 않으므로 IE와 호환되도록 하려면 canvas 만든 다음 excanvas 로 초기화하고 IE용 exCanvas.js를 추가하면 됩니다. 여기서는 IE를 명시적으로 고려하지 않습니다.
하지만 컴퓨터에서 브라우저 창을 변경하면 드로잉 보드의 크기가 그에 맞게 조정되지 않습니다. 해결책:
// autoSetSize 함수 실행을 기억하세요 function autoSetSize(){ canvasSetSize(); // 이 함수를 실행하면 캔버스의 너비와 높이가 먼저 설정됩니다 function canvasSetSize(){ let pageWidth = document.documentElement.clientWidth; pageHeight = document.documentElement.clientHeight; canvas.width = pageWidth = pageHeight } // 창 크기가 변경된 후 resize 이벤트가 트리거되어 캔버스 window.onresize = function(){ canvasSetSize() }}2. 그리기 기능 실현
구현 아이디어: 마우스 이벤트를 수신하고 drawLine() 메서드를 사용하여 기록된 데이터를 그립니다.
painting = false .mousedown ) painting true 로 설정하여 페인팅이 완료되고 마우스를 놓지 않음을 나타냅니다. 마우스 클릭을 기록합니다.mousemove ) 점이 기록되어 그려집니다. 마우스가 너무 빨리 움직이면 브라우저가 그리기 속도를 따라가지 못하고 점 사이에 틈이 생기기 때문에 그려진 점을 선( lineTo() )으로 연결해야 합니다.mouseup ) painting false 로 설정합니다. 참고: drawCircle 메소드는 실제로 작성할 필요가 없습니다. 이는 클릭을 시작할 위치를 모든 사람이 이해할 수 있도록 하기 위한 것입니다.
function listeningToUser() { // 브러시 상태를 초기화하는 변수를 정의합니다. let painting = false; // 브러시의 마지막 위치를 기록합니다. let lastPoint = {x: undefine, y: undefine} // 마우스 누름 이벤트 canvas.onmousedown = function (e){ 페인팅 = true; let x = e.clientX; let y = e.clientY = {'x':x,'y':y}; drawCircle(x,y,5); } //마우스 이동 이벤트 canvas.onmousemove = function(e){ if(painting){ let x = e.clientX; let y = e.clientY; :x,'y':y}; drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y); 마우스 해제 이벤트 canvas.onmouseup = function(){ painting = false; }}// 점 그리기 함수 function drawCircle(x,y,radius){ // 생성 후 그래픽 그리기 명령은 경로 경로를 생성합니다. context.beginPath(); // (x, y)를 중심으로 하고 반지름을 반지름으로 하여 // startAngle에서 시작하여 endAngle에서 끝나는 호(원)를 시계 반대 방향으로 그립니다(기본값은 시계 방향). )을 생성합니다. context.arc(x,y,radius,0,Math.PI*2); // 경로의 내용 영역을 채워 단색 그래픽을 생성합니다. context.fill(); // 경로를 닫은 후 그래픽 그리기 명령은 중간으로 리디렉션됩니다. context.closePath();}function drawLine(x1,y1,x2,y2){ //선 너비 설정 context.lineWidth = 10; //선 끝 스타일 설정. context.lineCap = round; // 선 사이의 연결 스타일을 설정합니다 context.lineJoin = round; // moveTo(x,y)는 지정된 x 및 y 좌표로 스트로크를 이동합니다. context.moveTo(x1,y1 ) / / lineTo(x, y)는 현재 위치에서 지정된 x 및 y 위치까지 직선을 그립니다. context.lineTo(x2,y2) // 선을 통해 그래픽 윤곽선을 그립니다. context.closePath();}3. 지우개 기능 구현
구현 아이디어:
eraserEnabled = false 설정합니다.click 이벤트를 수신하고, 지우개를 클릭하고, 지우개 상태를 변경하고, eraserEnabled = true 로 클래스를 전환하여 활성화된 효과를 얻습니다.eraserEnabled true 인 경우 마우스를 이동하고 context.clearRect() 사용하여 지우개를 구현합니다. 그런데 캔버스 API에서는 ClearRect 메소드가 픽셀을 지울 수 있지만, ClearRect 메소드는 직사각형 영역을 지운다는 사실을 발견했습니다. 결국 대부분의 사람들이 사용하는 지우개는 둥근 모양에 익숙하기 때문에 클리핑 영역이라는 강력한 기능이 도입되었습니다. 클립 방식입니다. 다음 코드는 context.clearRect() 사용하여 지우개를 구현합니다. 고무 사사프라를 더 잘 구현하는 방법을 알아보려면 단계별 섹션을 참조하세요.
let erar = document.getElementById(eraser);let erarEnabled = false;// ListenToUser 함수 실행을 기억하세요 function listeningToUser() { // ... 이전에 작성한 코드가 생략된다는 의미 // ... // 마우스 누르기 다음 이벤트 canvas.onmousedown = function(e){ // ... if(eraserEnabled){//지우개를 사용하려면 context.clearRect(x-5,y-5,10,10) }else{ lastPoint = {'x':x,'y':y} } } // 마우스 이동 이벤트 canvas.onmousemove = function(e){ let x = e.clientX; let y = e.clientY; !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) } } // ...}// 지우개 클릭 erar.onclick = function(){ erarEnabled = true; erar.classList.add('active');4. 화면 지우기 기능 구현
구현 아이디어:
요소 노드를 가져옵니다.
캔버스를 지우려면 지우기 버튼을 클릭하세요.
let reSetCanvas = document.getElementById(clear);//화면 지우기 실현 reSetCanvas.onclick = function(){ ctx.clearRect(0,0,canvas.width,canvas.height); setCanvasBg('white');}// 캔버스 배경색 재설정 function setCanvasBg(color) { ctx.fillStyle = color; 0, 캔버스.폭, 캔버스.높이);}5. 사진으로 저장 기능 구현
구현 아이디어:
let save = document.getElementById(save); // 이미지 다운로드 save.onclick = function(){ let imgUrl = canvas.toDataURL('image/png'); let saveA = document.createElement('a'); body.appendChild(saveA); saveA.href = imgUrl; saveA.download = 'mypic'+(new Date).getTime(); saveA.target = '_blank'; saveA.click();}6. 배경색 변경 기능 구현
구현 아이디어:
let selectBg = document.querySelector('.bg-btn');let bgGroup = document.querySelector('.color-group');let bgcolorBtn = document.querySelectorAll('.bgcolor-item');let penDetail = 문서. getElementById(penDetail);let activeBgColor = '#fff';//배경색 전환 구현 (let i = 0; i < bgcolorBtn.length; i++) { bgcolorBtn[i].onclick = function (e) { // 버블링 중지 e.stopPropagation() for (let i = 0; i < bgcolorBtn.length ; i++) { bgcolorBtn[i].classList.remove(active); this.classList.add(active); this.style.BackgroundColor; } }}document.onclick = function(){ bgGroup.classList.remove('active');}selectBg.onclick = function(e){ bgGroup.classList.add(' 활성'); e.stopPropagation();}7. 브러시 굵기 변경 기능 구현
구현 아이디어:
let range1 = document.getElementById('range1');let lWidth = 2;let ifPop = false;range1.onchange = function(){ console.log(range1.value); console.log(typeof range1.value) 두께. style.transform = 'scale('+ (parseInt(range1.value)) +')' console.log(thickness.style.transform ) lWidth = parseInt(range1.value*2);}// 선 그리기 함수 function drawLine(x1,y1,x2,y2){ // ... context.lineWidth = lWidth; // ...}// 브러시 브러시를 클릭합니다. . onclick = function(){ erarEnabled = false; Brush.classList.add('active') if(!ifPop); 팝업 상자 console.log('pop') penDetail.classList.add('active'); }else{ penDetail.classList.remove('active') } ifPop = !ifPop;}8. 브러시 색상 변경 기능 구현
구현 아이디어는 작업판의 배경색을 변경하는 것과 유사합니다.
let aColorBtn = document.getElementsByClassName(color-item);getColor();function getColor(){ for (let i = 0; i < aColorBtn.length; i++) { aColorBtn[i].onclick = function () { for ( i = 0; i < aColorBtn.length; aColorBtn[i].classList.remove(active); this.classList.add(active); activeColor = this.style.wallStyle = activeColor } } }}9. 변경사항 실행 취소 및 다시 실행 기능 구현
구현 아이디어:
canvasHistory 배열에 저장합니다(base64 이미지를 생성하는 스냅샷을 생성하려면 캔버스의 toDataURL() 메서드를 사용합니다).drawImage() 메서드를 사용하여 canvasHistory 배열에서 해당 인덱스의 스냅샷을 다시 그립니다. let undo = document.getElementById(undo);let redo = document.getElementById(redo);// ...canvas.onmouseup = function(){ painting = false; canvasDraw();}let canvasHistory = [];let step = -1; // 그리기 방법 function canvasDraw(){ step++; if(step < canvasHistory.length){ canvasHistory.length = step; 기록에 새 그리기를 추가합니다. canvasHistory.push(canvas.toDataURL());}//Undo 메서드 function canvasUndo(){ if(step > 0){ step--; // ctx.clearRect(0,0,canvas .width,canvas.height); let canvasPic = new Image(); canvasPic.src = canvasPic.onload = function () ctx.drawImage(canvasPic, 0, 0); } undo.classList.add('active'); }else{ undo.classList.remove('active'); Alert('실행 취소할 수 없음'); / 다시 실행 방법 function canvasRedo(){ if(step < canvasHistory.length - 1){ step++; let canvasPic = new Image(); canvasHistory[단계]; canvasPic.onload = function () { // ctx.clearRect(0,0,canvas.width,canvas.height) ctx.drawImage(canvasPic, 0, 0); 'active'); }else { redo.classList.remove('active') Alert('이미 최신 레코드입니다.'); }}undo.onclick = function(){ canvasUndo();}redo.onclick = function(){ canvasRedo();}10. 모바일 단말기와 호환 가능
구현 아이디어:
true , touch 이벤트가 사용됨 false , mouse 이벤트가 사용됨 // ...if (document.body.ontouchstart !== undefine) { // 터치 이벤트 사용 anvas.ontouchstart = function (e) { // 터치 시작} canvas.ontouchmove = function (e) { // 슬라이딩 시작 } canvas.ontouchend = function () { // 슬라이딩 끝 }}else{ // 마우스 이벤트 사용 // ... } // ... 4. 함정을 짓밟는다 문제 1: 컴퓨터의 브라우저 창을 변경하면 작업판이 적용되지 않습니다.해결책:
onresize 응답 이벤트 처리에서 얻은 페이지 크기 매개변수는 변경된 매개변수입니다.
창 크기가 변경되면 캔버스의 너비와 높이를 재설정합니다. 쉽게 말하면 창이 변경된 후 canvas.width 및 canvas.height를 다시 할당합니다.
// autoSetSize 함수 실행을 기억하세요 function autoSetSize(){ canvasSetSize(); // 이 함수를 실행하면 캔버스의 너비와 높이가 먼저 설정됩니다 function canvasSetSize(){ let pageWidth = document.documentElement.clientWidth; pageHeight = document.documentElement.clientHeight; canvas.width = pageWidth = pageHeight } // 창 크기가 변경된 후 resize 이벤트가 트리거되어 캔버스 window.onresize = function(){ canvasSetSize() }} 질문 2: 그리는 선의 폭이 상대적으로 작을 때는 괜찮지만, 두꺼워지면 문제가 발생합니다.해결책: 문서를 보고 방법을 알아내면 선을 그리는 코드 만 수정하면 됩니다.
// 선 그리기 함수 function drawLine(x1,y1,x2,y2){ context.beginPath(); context.lineWidth = lWidth; //------Add---- // 선 끝 스타일을 설정합니다. context.lineCap = round; // 선 사이의 접합 스타일 설정 context.lineJoin = round; //------Join---- context.moveTo(x1,y1); y2); 컨텍스트.스트로크(); 질문 3: 둥근 고무 사사프라스를 만드는 방법은 무엇입니까?해결책:
Canvas API에서는 ClearRect 메소드를 사용하면 픽셀을 지울 수 있지만, ClearRect 메소드는 직사각형 영역을 지울 수 있습니다. 결국 대부분의 사람들이 사용하는 지우개는 둥근 모양에 익숙하기 때문에 클리핑 영역의 강력한 기능, 즉 Clip 메소드를 도입한 것입니다. 사용법은 매우 간단합니다.
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();
위의 코드는 원형 영역의 삭제를 구현합니다. 즉, 먼저 원형 경로를 구현한 다음 이 경로를 클리핑 영역으로 사용한 다음 픽셀을 지웁니다. 한 가지 주의할 점은 먼저 그리기 환경을 저장하고 픽셀을 지운 후 그리기 환경을 재설정해야 한다는 것입니다. 재설정하지 않으면 향후 그리기는 해당 클리핑 영역으로 제한됩니다.
질문 4: 모바일 단말기와 어떻게 호환되나요?1.메타태그 추가
브라우저는 페이지가 휴대폰에 표시될 때 처음에 크기를 조정하기 때문에 메타 태그에 메타 뷰포트 속성을 설정하여 페이지 너비 = 사용자 장치 화면 너비를 조정하지 않도록 브라우저에 알릴 수 있습니다.
<메타 이름=뷰포트 content=width=device-width,initial-scale=1,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0/>/*페이지 너비=모바일 너비:width=device-width 사용자는 크기를 조정할 수 없습니다. user-scalable=스케일링 없음: 초기 스케일=1 최대 스케일링: 최대 스케일=1.0 최소 스케일링: 최소 스케일=1.0*/
2. PC 측과 달리 모바일 측에서는 거의 모든 터치 이벤트가 사용됩니다.
모바일 쪽에서는 터치 이벤트를 사용하기 때문에 H5 속성인 touchstart/touchmove/touchend를 사용하지만, PC 쪽에서는 마우스 이벤트만 지원하므로 기능 감지가 필요합니다.
touch 이벤트에서는 .touches[0].clientX , .touches[0].clientY 를 통해 좌표를 구하는데, 이는 mouse 이벤트와 구별되어야 합니다.
글쎄, 그것은 큰 문제가 아닙니다. 단지 내가 context.beginPath();를 작성하는 것을 놓쳤고 그것에 대한 버그를 해결하는 데 시간이 걸렸다는 것이 생각나네요. 코멘트는 표준화되어 있지 않습니다. 프로그래밍도 표준화되어 있지 않습니다. 눈물이 나네요. 문서화된 작동 사양에 따라 작동하는 것이 더 낫습니다. 냄새가 너무 좋습니다! ! !
위의 내용은 이 기사의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다. 또한 모든 분들이 VeVb Wulin Network를 지지해 주시길 바랍니다.