この記事では主に以下の内容を紹介します。
名前: スマート描画ボード
テクノロジースタック: HTML5、CSS3、JavaScript、モバイル
機能の説明:
プロジェクトアドレス プレビューアドレス
プレビュー
PC プレビュー:
モバイル プレビュー:
上記のプレビューを読んで、 Smart Drawing Pad を体験したら、興奮しているかどうかに関係なく、とにかく満足していることを忘れないでください。プロジェクトの結果は達成されました。これまではナンセンスなことをたくさん言いましたが、ここで必要な効果を達成するためにコードを入力することができます。 ! !
注: 以下のプロジェクトの効果は主に JavaScript に関連しています。以下は実装のアイデアを提供するコードのみであり、コード全体ではありません。
3. プロジェクトの成果を段階的に達成する(1) 分析ページ
ユースケース図を通じて、ユーザーがウェブサイトにアクセスするためにどのような機能を使用できるかが分かります。
ユーザーができること:
(2) HTMLレイアウト
htmlを書くときにcssファイルとjsファイルを導入しました
<!DOCTYPE html><html lang=ja><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=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>背景色の選択:</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: grey;></li> <li class=bgcolor-item style=background-カラー: #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>ペンのサイズ</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-color clearfix> <li class=color-item active style=background-color: black;></リ> <リ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>不透明度</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. 準備
まず、描画ボードであるコンテナを準備します。これはまったくのナンセンスです。
<canvas id=canvas></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;ページの高さ = document.documentElement.clientHeight; キャンバスの幅 = ページの高さ = ページの高さ;ウィンドウ サイズが変更されると、サイズ変更イベントがトリガーされて、キャンバスの幅と高さがリセットされます。2.描画機能の実現
実装のアイデア: マウス イベントをリッスンし、 drawLine()メソッドを使用して記録されたデータを描画します。
painting = false 。mousedown )、 painting trueに設定します。これは、ペイントが行われていてマウスが放されていないことを示します。マウスのクリックを記録します。mousemove )。 マウスの動きが速すぎるとブラウザの描画速度が追いつかず、点と点の間に隙間ができてしまうため、描いた点を線で結ぶ必要があります( lineTo() )。mouseup )、 painting falseに設定します。注: 実際には、 drawCircleメソッドを記述する必要はありません。これは、どこをクリックし始めるかを誰もが理解できるようにするためです。
function listenToUser() { // ブラシの状態を初期化する変数を定義します let Painting = false // ブラシの最後の位置を記録します let lastPoint = {x: 未定義, y: 未定義} // マウス プレス イベント Canvas.onmousedown; = 関数 (e){ 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 newPoint = {'x' :x,'y':y};drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y);マウスリリースイベント Canvas.onmouseup = function(){ Painting = false; }}// 描画ポイント関数 functiondrawCircle(x,y,radius){ // 生成後、グラフィックス描画コマンドがポイントします。パス パスを生成します。 context.beginPath(); // (x, y) を中心、半径を半径として、反時計回りで指定された方向に、// startAngle から始まり endAngle で終わる円弧 (円) を描画します (デフォルトは時計回り) ) を生成します。 context.arc(x,y,radius,0,Math.PI*2); // パスのコンテンツ領域を塗りつぶしてソリッドグラフィックを生成します context.fill(); // パスを閉じた後、グラフィックを生成します描画コマンドは中央のコンテキストにリダイレクトされます。 context.closePath();}functiondrawLine(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.blood(); context.closePath();}3. 消しゴム機能を実装する
実装のアイデア:
eraserEnabled = falseに設定します。clickイベントをリッスンし、消しゴムをクリックし、消しゴムの状態eraserEnabled = trueを変更し、クラスを切り替えてアクティブ化された効果を実現します。eraserEnabledがtrueの場合、マウスを移動し、 context.clearRect()を使用して Eraser を実装します。しかし、canvas API では、clearRect メソッドはピクセルをクリアできますが、結局のところ、ほとんどの人の消しゴムは丸いことに慣れているため、クリッピング エリアの強力な機能が導入されていることがわかりました。クリップ方式です。次のコードはcontext.clearRect()を使用して消しゴムを実装します。ラバーサッサフラスをより適切に実装する方法については、ステップバイステップのセクションを参照してください。
let Eraser = document.getElementById(eraser);let EraserEnabled = false;// listenToUser 関数を実行することを忘れないでください function listenToUser() { // ... 以前に記述されたコードが省略されることを意味します // ... // マウスを押す次のイベント 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); var newPoint = {'x':x,'y':y};drawLine(lastPoint.x, lastPoint.y,newPoint.x, newPoint.y) } } // ...}// 消しゴムをクリックします。 Eraser.onclick = function(){ EraserEnabled = true; Brush.classList.remove('active');}4. 画面クリア機能の実装
実装のアイデア:
要素ノードを取得します。
キャンバスをクリアするには、「クリア」ボタンをクリックします。
let reSetCanvas = document.getElementById(clear);// 画面クリアを実現します reSetCanvas.onclick = function(){ ctx.clearRect(0,0,canvas.width,canvas.height);}//キャンバスの背景色をリセットする関数 setCanvasBg(color) { ctx.fillStyle = color; 0、canvas.width、canvas.height);}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'+(新しい日付).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 = document。 getElementById(penDetail);let activeBgColor = '#fff';//背景色の切り替えを実装しました(let i = 0; i < bgcolorBtn.length; i++) { bgcolorBtn[i].onclick = function (e) { // バブリングを停止します。 e.stopPropagation(); (let i = 0; i < bgcolorBtn.length ; i++) { bgcolorBtn[i].classList.remove(active); this.classList.add(active); this.style.backgroundColor; setCanvasBg(activeBgColor); } }}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);}// 線描画関数 functiondrawLine(x1,y1,x2,y2){ // ... context.lineWidth = lWidth; // ...}// ブラシをクリックします。 .onclick = function(){ EraserEnabled = false; Brush.classList.remove('active');ポップアップボックス console.log('pop')penDetail.classList.add('active') }else{penDetail.classList.remove('active'); }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); activeColor = this.style.backgroundColor; } }}9. 変更を元に戻すおよびやり直しの機能を実装する
実装のアイデア:
canvasHistory配列に保存します (スナップショットを生成するには、Canvas のtoDataURL()メソッドを使用します。これにより、base64 イメージが生成されます)。drawImage()メソッドを使用して、 canvasHistory配列内の対応するインデックスのスナップショットを再描画します。 let undo = document.getElementById(undo);let redo = document.getElementById(redo);// ...canvas.onmouseup = function(){ Painting = false; CanvasDraw();}let CanvasHistory = [];let step = -1; // 描画メソッド関数 CanvasDraw(){ step++; if(step < CanvasHistory.length = step) //履歴に新しい描画を追加 CanvasHistory.push(canvas.toDataURL());}//元に戻すメソッド function CanvasUndo(){ if(step > 0){ step--; .width,canvas.height); let CanvasPic = new Image(); CanvasPic.onload = function (); ctx.drawImage(canvasPic, 0, 0); } undo.classList.add('active'); }else{ undo.classList.remove('active'); } / / やり直しメソッド function CanvasRedo(){ if(step < CanvasHistory.length - 1){ step++; let CanvasPic = new Image(); CanvasHistory[ステップ]; CanvasPic.onload = function () { // ctx.clearRect(0,0,canvas.width,canvas.height); } redo.classList.add( 'アクティブ'); }else { redo.classList.remove('アクティブ')alert('すでに最新のレコード'); }}undo.onclick = function(){ CanvasUndo();}redo.onclick = function(){ CanvasRedo();}10.モバイル端末にも対応
実装のアイデア:
true 、 touchイベントが使用されます。 false 、 mouseイベントが使用されます。 // ...if (document.body.ontouchstart !== unknown) { // タッチイベントを使用 anvas.ontouchstart = function (e) { // タッチ開始} Canvas.ontouchmove = function (e) { // スライド開始} Canvas.ontouchend = function () { // スライドの終了 }}else{ // マウスイベントを使用 // ... } // ... 4. 落とし穴を踏みつける問題 1: コンピュータのブラウザ ウィンドウを変更すると、描画ボードが適応しません。解決:
onresize 応答イベント処理では、取得されるページ サイズ パラメーターが変更後のパラメーターになります。
ウィンドウサイズが変わったらcanvasの幅と高さを再設定する 簡単に言うと、ウィンドウが変わったらcanvas.widthとcanvas.heightを再割り当てします。
// autoSetSize 関数を必ず実行してください function autoSetSize(){ CanvasSetSize(); // この関数を実行すると、最初にキャンバスの幅と高さが設定されます function CanvasSetSize(){ let pageWidth = document.documentElement.clientWidth;ページの高さ = document.documentElement.clientHeight; キャンバスの幅 = ページの高さ = ページの高さ;ウィンドウ サイズが変更されると、サイズ変更イベントがトリガーされて、キャンバスの幅と高さがリセットされます。疑問2:描いた線の幅が比較的細いうちは大丈夫ですが、太くなると問題が発生します。解決策: ドキュメントを参照して方法を見つけてください。線を描画するコードを変更するだけです。
// 線描画関数 functiondrawLine(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/>/*Page width=Mobile width:width=device-width ユーザーは拡大縮小できません : user-scalable=スケーリングなし:initial-scale=1 最大スケーリング:maximum-scale=1.0 最小スケーリング:minimum-scale=1.0*/
2. ほとんどすべてのタッチイベントは、PC 側とは異なり、モバイル側で使用されます。
モバイル側ではタッチ イベントを使用するため、H5 属性の touchstart/touchmove/touchend が使用されますが、PC 側ではマウス イベントのみがサポートされるため、機能検出が必要です。
touchイベントでは、座標は.touches[0].clientXおよび.touches[0].clientYを通じて取得されます。これはmouseイベントとは区別する必要があります。
まあ、それは大きな問題ではありません。context.beginPath(); を書き忘れて、そのバグを解決するのに時間を費やしただけです。コードの最初の行が数千万行あることを思い出しました。コメントは標準化されていない、プログラミングは標準化されていない、そして私の同僚は 2 つの行を持っています。文書化された動作仕様に従って動作する方が良いです。とても良い匂いがします。 ! !
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。