最近、作成者は、リングの周りにテキストのグループを表示するという要件を持っています。テキストは、リングの周りの小さな青い点に対応します。マウスをリングの上に置くと、三角形が放射され、テキストが表示されます。まずアニメーション効果を見てみましょう。
上の図に示すように、対応する小さな青い点にマウスを置くと、三角形のような光線が放射される必要があり、対応するテキストが三角形の外側に表示され、小さな青い点が小さな白い点になります。
ユーザーが上にコンテンツを入力すると、下のリングの周囲にコンテンツが追加されます。上の写真に示すように。
作者の当初のアイデアは、下の図の動的なセカンダリ メニューのように、CSS を使用して実装することでした。
ただし、リングの端のコンテンツは可変であり、リングの周囲に配置する必要があることを考慮すると、CSS を実装するのは難しいかもしれません。なんと、作者はそれを実現するためにキャンバスを使用することにしました。 (作者は最近canvasを勉強したばかりです。何か間違っている点があれば、修正を受け付けます。)
実装プロセス:初め:
コードの html 部分は次のとおりです。
<canvas style=margin-left: 50px;padding-top: 20px; display:block; id=canvas > 現在のブラウザのバージョンは Canvas をサポートしていません。
具体的な実装手順は次のとおりです。
1. 大きな円を描きます。
Canvas メソッドを使用します: context.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);
x、y: 円の中心座標、radius: 円の中心半径、startAngle: 開始ラジアンの描画、endAngle: 終了ラジアンの描画、[、反時計回り]: 円弧を時計回りに描くか反時計回りに描くかを示すオプションのパラメーター。
描画の便宜上、作者はキャンバスの原点を以前の左上隅からキャンバスの中央に移動しました。
著者が計算したリングの半径はr-80です
Canvas.width = 500canvas.height = 500//キャンバスの中心の半径を計算 let r = 500 / 2//インターフェースの初期化時にキャンバスの原点をキャンバスの中心に移動 ctx.translate(r ,r) //ブラシを動かして丸くする
具体的なコードは次のとおりです。
//キャンバスの初期化 let Canvas = document.getElementById('canvas')let ctx= Canvas.getContext('2d')let rate = getPixelRato(ctx)canvas.width = 500canvas.height = 500//中心の半径を計算するキャンバスの let r = 500 / 2// インターフェイスが初期化されるとき、キャンバスの原点をキャンバスの中心に移動します ctx.translate(r,r) //ブラシを円に移動します ctx.lineWidth = 3; //ブラシの線幅を設定します ctx.beginPath() //ブラシを開始します//円のエッジのグラデーションエッジ色を描画します var arcColor = ctx.createLinearGradient(-170, -170, 0, 170)arcColor.addColorStop(0, '#8ec1ff')arcColor.addColorStop(0.2, '#83beff')arcColor.addColorStop(0.5, '#75b1ff')arcColor.addColorStop(0.7,'#5998ff')arcColor.addColorStop(1, '#2065ff')ctx .ストロークスタイル= arcColor;//ブラシの色を設定します ctx.arc(0,0,r - 80,0,2*Math.PI,false) //円を描画します、座標 0,0、半径 250-80、完全な円(0 ~ 360 度)、false は時計回りを意味します ctx.closePath()ctx.ストローク() //描画
抽選結果は以下の通り
2. リングの中央に背景画像を描画します(現在のキャンバスの原点がキャンバスの中心になります)
drawImage(image, dx, dy, dWidth, dHeight)
画像: <img> 画像、SVG 画像、Canvas 要素自体などの Canvas 画像リソース。
dx、dy: Canvas キャンバス上に画像を配置する領域を計画します。dx は、この領域の左上隅の水平座標と垂直座標です。
dWidth、dHeight: 画像を配置するキャンバス上の領域、この領域の幅と高さを計画します。
以下の座標は著者が計算したものです
let image = new Image()image.src = 'image/quan.png'image.onload = () => { // 原点を中心に移動 ctx.drawImage(image,-140,-140,280,280)}
描画結果は以下の通りです。
3. リング上にテキストと小さな点を描画します(現在のキャンバスの原点はキャンバスの中心です)
テキストと小さなドットの描画ターゲット:
3.1 大きなリング上に小さなドットが均等に表示される
3.2 小さなドットの外側に文字が少し散らばっている
解決:1. 著者は配列を使用して現在の単語を保存します
let textArr = ['広い海と空','技術力','豊富な資金','保守管理','安心して満足して暮らし、働ける','花を眺める','最後の仕上げをする','カスを取り除く、「風に逆らう」、「キャリア開発」]
2.小さなドットの数と単語の数は同じなので、両方の数が上記の配列textArrの長さになります。
3. 完全な円のラジアンは 2π です。小さなドットがリングを均等に分割するために、作成者は最初に各小さなドットが位置する点のラジアンを計算します。
for(let i = 0;i<lengths;i++){ // ラジアンを計算 let rad = 2*Math.PI/lengths*i}
4. 三角関数に従って、キャンバス上の現在の小さな点の座標 (x, y) を計算できます (現在のキャンバスの原点はキャンバスの中心です)。
その中で、ラジアン、小さな点、リング、リング半径とキャンバス原点の関係について、著者はそれらを説明するために絵を描きました。
テキストの座標を計算します。
// 小さな円の中心の座標を計算します let x = (r - 40)*Math.cos(rad)let y = (r - 40)*Math.sin(rad)
小さなドットの座標を計算します。小さなドットの中心がリング上にある必要があるため、計算された水平座標と垂直座標は次のようになります。
// テキストの座標を計算します let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad)
具体的なコードは次のとおりです。
// テキストを描画します ctx.font = '13px Arial'ctx.textAlign = 'center'ctx.textBaseline = 'middle'ctx.fillStyle=#000000let length = textArr.lengthtextArr.forEach(function(text,i){ //ラジアンlet rad = 2*Math.PI/lengths*i // 小さな円の中心の座標を計算 let x = (r - 40)*Math.cos(rad) let y = (r - 40)*Math.sin(rad) ctx.fillText(text,x+0.5,y+0.5)});// 小さな点を描画します for(let i = 0;i<lengths;i++){ // // rad = 2*Math.PI/lengths*i にしましょう x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad)// // エッジに小さな灰色の半透明のドットを描画します ctx.beginPath() ctx.fillStyle = 'rgba(226,235,250, 0.8)' ctx.arc(x,y,8,0,2*Math.PI,false) ctx.closePath() ctx.fill() // 小さな青い点を描画します ctx.beginPath() ctx.fillStyle = '#208fe5' ctx.arc(x,y,4,0,2*Math.PI,false) ctx.closePath( ) ctx 。埋める() }
描画結果は以下の通りです。
4. それぞれの小さなドットの外側に三角形を描きます (現在のキャンバスの原点はキャンバスの中心です)。
4.1 三角形の形を描きたいので、三角形を描くアイデアは、現在の小さな点の中心を開始点として両側に線を描画し、ctx.fill() を使用して形を閉じ、内部をグラデーションカラーで塗りつぶします。
三角形を描画します。座標は自動的に計算されます。著者は横軸で 35、縦軸で 70 を足したり引いたりします (好きなようにしてください、ははは)
//ブラシを開始 ctx.beginPath() ctx.moveTo(x,y) ctx.lineTo(x-35,y+70) ctx.lineTo(x+35,y+70) ctx.closePath()
三角形の下にテキストを描画します: (前のテキストと区別するために、ここではテキストに赤を使用しました)
ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75)
具体的なコードは次のとおりです。
for(let i = 0;i<lengths;i++){ // // let rad = 2*Math.PI/lengths*i let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad) // // 三角形を描画 // // ctx.rotate( -Math.PI / 4) ctx.beginPath() // ブラシを開始します ctx.moveTo(x,y) ctx.lineTo(x-35,y+70) ctx.lineTo(x+35,y+70) ctx.closePath() // // カラーグラデーションを設定します- - ->中心から両側に色を追加 var sColor = ctx.createLinearGradient (x,y,x+18,y+50) sColor.addColorStop(0,'rgba(106,128,243,0.5)') sColor.addColorStop(0.6,'rgba(83,183,243,0.5)') sColor.addColorStop(0.7,'rgba(129,200,224,0.5)') sColor.addColorStop(0.8,'rgba(130,219,251,0.5)') sColor.addColorStop(1,'rgba(195,228,223,0.5)') ctx.fillStyle= sColor ctx.fill() ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75)}
描画結果は以下の通りです。
4.2 要件は、各三角形の方向が外側に広がることですが、三角形の方向は下向きになっているため、キャンバスの回転方法を使用する必要があります。
ctx.save() ctx.translate(x,y) // 回転角度は各小さな点を中心にします ctx.rotate( rad - Math.PI/2 ) // 小さな点があるため ctx.translate(- x, - y) . 三角形とテキストを描画するコードを省略します。
計算からわかるように、小さなドットの中心を回転の開始点として使用すると、三角形の回転の円弧は、現在の小さなドットの円弧から π/2 を引いた値になるはずです。回転の開始位置は常に変化するためです。 x 座標軸の正の方向から始まります。つまり、0 ラジアンから始まりますが、三角形はすべて π/2 ラジアンになります。つまり、次のようになります。
回転のラジアン = 小さなドットのラジアン - π/2
回転するときは、キャンバスの状態保存メソッド save() を忘れずに使用してください。
restore() は、保存された Canvas 状態をスタックの最上位から順番にポップします。保存された Canvas 状態がない場合、このメソッドの実行に変更はありません。
最後に必ずrestore()メソッドを使用することを忘れないでください。この時点で、著者は後悔の涙を流しました。 。 。
具体的なコード:
for(let i = 0;i<lengths;i++){ // // let rad = 2*Math.PI/lengths*i let x = (r - 80)*Math.cos(rad) let y = (r - 80)*Math.sin(rad) // S の三角形を描画します ctx.save() // 小さなドットが先頭にあるため、回転角度は各小さなドットを中心とします ctx.translate(x,y) ctx.rotate( rad - Math.PI/2 ) ctx.translate(-x, -y) // ブラシを開始します ctx.beginPath() ctx.moveTo(x,y) ctx.lineTo(x-35,y+ 70 ) ctx.lineTo(x+35,y+70) ctx.closePath() //カラーグラデーションを設定--->中心から両側にカラー変数を追加しますsColor = ctx.createLinearGradient (x,y,x+18,y+50) sColor.addColorStop(0,'rgba(106,128,243,0.5)') sColor.addColorStop(0.6,'rgba(83,183,243,0.5)') sColor.addColorStop(0.7,'rgba(129,200,224,0.5)') sColor.addColorStop(0.8,'rgba(130,219,251,0.5)') sColor.addColorStop(1,'rgba(195,228,223,0.5)') ctx.fillStyle= sColor ctx.fill() ctx.fillStyle= '#e3211c' ctx.fillText(textArr[i],x,y+75) ctx.restore()}
結果をプロットします。
よく見てください、何ですか? ? ?回転の問題により、一部のテキストが上下逆さまになることが観察によりわかりました。ラジアンが π より大きい場合、テキストは上下逆さまになります。
if 判断の波を書く時が来ました。 。 。 。
テキストを回転する方法:
functionrotateContext(ctx, x, y,degree) { // テキストを回転 ctx.translate(x, y) // ctx.rotate(degree * Math.PI / 180) ctx.rotate(degree) ctx.translate(-x 、 -y) }
ラジアンが π より大きい小さなドットを特定します。
if (rad > Math.PI) { // テキストは三角形の端に表示される必要があるため、テキストは、 // 回転後も常に三角形の端に維持されるように、三角形とともに回転する必要があります。ラジアンが π より大きい場合、テキストが表示されます。問題を逆にします。テキストを回転します。 ctx.save() ctx.beginPath() // テキストを回転します。rotateContext(ctx, x, y+75, Math.PI) ctx.font = '13px Arial' ctx.textAlign = 'center' ctx.fillStyle = #ff2238 ctx.fillText(textArr[i], x, y+ 75) ctx.restore()} else { ctx.fillStyle = '#ff2238' ctx.fillText(textArr[i] ]、x、y + 75)}
描画結果は以下の通りです。
勝利を楽しみにしていますが、少なくとも大まかなレイアウトはできており、同志たちはまだ努力する必要があります。 !
5. 以下の実装は、マウスを小さな点の上に置くと、三角形の端の三角形とその三角形の端のテキストが表示されますが、円の端のテキストは表示されません。
アイデア:1. マウス入力イベントをキャンバスにバインドします。
2. キャンバス上の現在のマウス位置の座標が小さな点の近くの座標と等しいかどうかを確認し、一致する場合は、小さな点に対応する三角形を表示します。
5.1 Mousemove イベントをキャンバスにバインドします。マウスはイベントの上にあります。
Canvas.addEventListener('mousemove',clickEvent)
5.2 キャンバス上のマウスの現在の座標を計算する
計算方法は、DOM 上のマウスの現在の座標を使用して、キャンバスの左または上からの距離を引き、キャンバスの距離を計算します。
以下の図のdrawOne メソッドは描画メソッドであり、この記事の後半で説明します。
function clickEvent() { // マウス位置の座標 let x =event.clientX - Canvas.getBoundingClientRect().left let y =event.clientY - Canvas.getBoundingClientRect().topdrawOne(x,y)}
5.3では、上記で計算したキャンバス上のマウスの座標はキャンバスの左上隅を原点として計算していますが、現在のキャンバスの原点はすでにキャンバスの中心(250,250)に移動しているため、使用するとクリックが小さな点であるかどうかを判断する現在のキャンバス上の小さなドットの座標と比較するには、水平座標と垂直座標の両方から 250 を引く必要があります。判定を行っているときに、なぜ y 方向に差があるのかわかりません。著者の値は 250 ではなく 260 です。したがって、著者は 260 を y 方向に減算しました。
コードは次のとおりです。
このうち、Cx、Cyはキャンバス上のマウスの座標(キャンバスの左上隅が原点)、x、yは現在の小さなドットの座標、
筆者が小ドットの中心付近15pxの位置を直接計算したところ、全ての三角形が表示され、小ドットが白くなりました。
最も重要なことは、再描画するたびに前のキャンバスをクリアする必要があるということです。キャンバスをクリアするには、忘れずに clearRect メソッドを使用してください。
XX = Cx - 250let YY = Cy- 260let leftX = x - 15let rightX = x + 15let topY = y - 15letbottomY = y + 15if (XX >= leftX && XX <= rightX && YY <=bottomY && YY > = topY ) {//クリックされます。 。 。 。 。 。 //途中に描画コードを書く}
コードの後にはリンクが続きます。
6. インターフェイス上で入力を定義し、変更イベントを入力にバインドします。
実装: 入力の値が変更されるたびにインターフェイスが再描画されます。
htmlコード:
<input type=text id=inpt style=margin-left: 100px;margin-top: 50px placeholder=入力してください...>
jsコード:
let inpt = document.getElementById('inpt') inpt.addEventListener('change', function () { if (inpt.value !== '') { textArr.push(inpt.value)drawAll(2) //これこのメソッドは描画メソッドであり、ソース コードは記事の後半で説明します。}})
7. インターフェイスをクリックして再描画するたびに、問題が発生します。
以下に示すように:
スライドするたびにマウスの座標が変わるため、リングの周囲のコンテンツをクリアして再描画する必要があります。したがって、動的な効果を実現するには、キャンバスをクリアする必要があります。
clearRect() は、キャンバス アニメーションの描画で非常によく使用されます。これは、キャンバスのコンテンツを継続的にクリアしてから、アニメーション効果を形成するために描画します。
clearRect() は、Canvas 要素のキャンバス内の長方形の領域を透明にすることができます。
context.clearRect(x, y, 幅, 高さ);
x、y: 長方形の左上隅の x、y 座標。
幅、高さ: 消去された長方形領域の幅と高さ。
clearRect()はキャンバスの四角形の領域しかクリアできないため、クリアするたびに真ん中の背景画像も一緒にクリアされてしまいます。
そのため、背景画像は毎回再読み込みする必要があり、画像の読み込みにある程度の時間がかかるため、表示されるたびに背景画像が点滅してしまいます。
解決:drawImage(image, dx, dy, dWidth, dHeight)
パラメータ image: <img> 画像、SVG 画像、Canvas 要素自体などの Canvas 画像リソース。
その後、他のキャンバスを使用して画像をキャッシュできます。
追加のキャンバスを使用して背景画像を描画しますが、そのキャンバスはインターフェイスに表示されません: display:none。その後、それを使用してキャンバスをクリアし、キャッシュされたキャンバス オブジェクトを表示するキャンバスの中央に直接レンダリングします。画像を一度読み込むのは時間がかかります。
htmlコード:
<canvas width=280 height=280 style=margin-left: 50px;padding-top: 20px; id=canvas2> </canvas>
jsコード:
//再描画されたイメージの点滅の問題を解決するにはキャッシュを使用します。 var tempCanvas = document.getElementById('canvas2')const tempCtx = tempCanvas.getContext('2d')tempCanvas.width = 280let image = new Image( )image.src = 'image/quan.png'image.onload = () => { //原点が中心に移動 tempCtx.drawImage(image,0,0,280,280)}
キャンバスをクリアした後、画像を再描画するときに、キャッシュされた Canvas:tempCanvas を直接描画します。
// キャッシュされたキャンバスをインターフェイスに直接描画します (中間タイヤ インターフェイスがキャッシュされます) ctx.drawImage(tempCanvas,-140,-140)
さて、成功しました。結果の画像は次のとおりです。
ソースコードのアドレスは以下のとおりです。
https://github.com/Linefate/Dynamic-effect-of-canvas-ring.git
要約する上記は、html5 キャンバスを使用してリング アニメーションを描画するための編集者による紹介です。ご質問があれば、メッセージを残してください。編集者がすぐに返信します。また、VeVb武道サイトを応援してくださった皆様、誠にありがとうございました!