質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

1045閲覧

Canvasで記述した文字に慣性付きの動きを実装したい

Karna554

総合スコア10

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2020/05/19 22:11

前提・実現したいこと

https://groxi.jp/

先日からこちらのサイトのTOPの文字がマウスカーソルの位置によって移動するところを実装しています。

発生している問題・エラーメッセージ

文字がマウスカーソルの位置に応じて動く部分までは実装できたのですが、そこからその動きに慣性をつけるやり方が見当がつきません。

エラーメッセージ

該当のソースコード

Javascript

1const brown_text_name = ['brown_a_1', 'brown_a_2', 'brown_c', 'brown_H', 'brown_i', 'brown_M', 'brown_p', 2'brown_P_1', 'brown_P_2', 'brown_s_1', 'brown_s_2', 'brown_T', 'brown_v']; 3 4// 茶色文字?の設定(X座標、Y座標、角度、フォントの種類&サイズ, 色, 出力文字) 5var brown_text = { 6 7 'brown_a_1' : {'pointX': 1144, 'pointY': 333, 'angle': 20, 'font_size': '200px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'a'}, 8 'brown_a_2' : {'pointX': 823, 'pointY': 427, 'angle': -20, 'font_size': '120px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'a'}, 9 'brown_c' : {'pointX': 1097, 'pointY': 605, 'angle': 20, 'font_size': '120px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'c'}, 10 'brown_H' : {'pointX': -118, 'pointY': 290, 'angle': 340, 'font_size': '330px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'H'}, 11 'brown_i' : {'pointX': 1269, 'pointY': 714, 'angle': 20, 'font_size': '230px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'i'}, 12 'brown_M' : {'pointX': 430, 'pointY': 12, 'angle': 20, 'font_size': '240px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'M'}, 13 'brown_p' : {'pointX': 1321, 'pointY': 656, 'angle': -10, 'font_size': '200px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'p'}, 14 'brown_P_1' : {'pointX': 669, 'pointY': 0, 'angle': -25, 'font_size': '350px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'P'}, 15 'brown_P_2' : {'pointX': 1074, 'pointY': 113, 'angle': -25, 'font_size': '230px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'P'}, 16 'brown_s_1' : {'pointX': 414, 'pointY': 496, 'angle': -30, 'font_size': '270px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 's'}, 17 'brown_s_2' : {'pointX': 342, 'pointY': 656, 'angle': -20, 'font_size': '120px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 's'}, 18 'brown_T' : {'pointX': 209, 'pointY': 178, 'angle': -20, 'font_size': '150px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'T'}, 19 'brown_v' : {'pointX': 927, 'pointY': 311, 'angle': -20, 'font_size': '150px Fredoka One', 'color': 'rgba(88, 56, 34, 1)', 'value': 'v'}, 20 21}; 22 23// 描画用関数 24function draw_canvas() { 25 26 // TOP部分の描画コンテキスト取得 27 var canvas = document.getElementById('top_canvas'); 28 29 // 描画範囲設定 30 canvas.width = window.innerWidth; 31 canvas.height = 1900; 32 33 // コンテキスト取得 34 if (canvas.getContext) { 35 var context_brown = canvas.getContext('2d'); // 茶色文字用コンテキスト 36 } 37 38 context_brown.textAlign = "left"; 39 context_brown.textBaseline = "top"; 40 41 // 茶色文字描画 42 for (let i = 0; i <= brown_text_name.length - 1; i++) { 43 44 context_brown.save(); 45 46 var x = brown_text[brown_text_name[i]]['pointX']; 47 var y = brown_text[brown_text_name[i]]['pointY']; 48 context_brown.font = brown_text[brown_text_name[i]]['font_size']; 49 context_brown.fillStyle = brown_text[brown_text_name[i]]['color']; 50 context_brown.translate(x, y); 51 context_brown.rotate((brown_text[brown_text_name[i]]['angle'] ) * Math.PI / 180); 52 context_brown.translate(-x, -y); 53 context_brown.fillText(brown_text[brown_text_name[i]]['value'], x, y); 54 55 context_brown.restore(); 56 57 } 58} 59 60ar preX = 0; 61var preY = 0; 62 63// 文字の移動用 64window.onload=function(){ 65 66 draw_canvas(); // フォント反映 67 68 //マウス移動時のイベントをBODYタグに登録する 69 document.body.addEventListener("mousemove", function(e){ 70 71 //座標を取得する 72 var mX = e.pageX; //X座標 73 var mY = e.pageY; //Y座標 74 75 var cX = e.pageX; 76 var cY = e.pageY; 77 78 var mX = preX - cX; 79 var mY = cY - preY; 80 81 preX = cX; 82 preY = cY; 83 84 var c = 100; // 補正変数 85 86 for (let i = 0; i <= brown_text_name.length - 1; i++) { 87 brown_text[brown_text_name[i]]['pointX'] += mX / c; 88 brown_text[brown_text_name[i]]['pointY'] += mY / c; 89 } 90 91 draw_canvas(); // 再描画 92 }); 93}

試したこと

https://qiita.com/edo_m18/items/f0587c3bcd4fb8e2bc50

こちらのサイトを見ながら色々検討してみたのですが、どうにもやり方が見えてきません

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/05/20 22:28

ガン見しています。なんか色々無駄が多いかな。理解するのに時間がかかった。 ちょっと時間をくださいな。 ちなみに for (let i = 0; i <= brown_text_name.length - 1; i++) は、 for (let i = 0; i < brown_text_name.length; i++) にすると、短くなるよ!
guest

回答1

0

ベストアンサー

見回しているうちに原形をとどめなくなってしまいました。ごめんなさい。
最後の数行を複数定義すれば、同一のページに似たような機能を複数定義できます。
P2 を改造して P3 を作られると 奥行きを醸し出す3D的なものになると思います。
元のプログラムは、文字の座標を直接弄っていましたが、それは好ましくない。
なので、相対的な座標と元座標を加算して描画しています。
それと慣れてきたらグローバル変数を使わないようにしましょう!

javascript

1<!DOCTYPE html> 2<meta charset="utf-8"> 3<title>Canvas</title> 4 5<body> 6<canvas id="top_canvas"></canvas> 7 8<script> 9//-------------------------------- 10//2次の点 11 12class P2 { 13 constructor (x = 0, y = 0) { this.x = x; this.y = y; } 14 multi ({x, y}) { this.x *= x; this.y *= y; return this; } 15 add ({x, y}) { this.x += x; this.y += y; return this; } 16 sub ({x, y}) { this.x -= x; this.y -= y; return this; } 17 copy () { return new P2 (this.x, this.y); } 18} 19 20 21//-------------------------------- 22//文字を定義してオブジェクトにする 23 24class Character { 25 constructor (value, point, angle, font, fillStyle) { 26 this.p = point; 27 this.value = value; 28 this.angle = angle * Math.PI / 180; 29 this.font = font; 30 this.fillStyle = fillStyle; 31 } 32 33 draw (canvas, offset) {//与えられた canvasオブジェクトを利用して、文字を描く機能を持たせる 34 let 35 { ctx } = canvas, 36 { value, p, angle, font, fillStyle } = this, 37 { x, y } = offset.copy ().add (p); 38 39 ctx.textAlign = "left"; 40 ctx.textBaseline = "top"; 41 ctx.font = font; 42 ctx.fillStyle = fillStyle; 43 ctx.save (); 44 ctx.translate (x, y); 45 ctx.rotate (angle); 46 ctx.translate (-x, -y); 47 ctx.fillText (value, x, y); 48 ctx.restore (); 49 } 50 51 static create (value = '', x = 0, y = 0, angle = 0, font = '20px Fredoka One', fillStyle = 'black') { 52 return new Character (value, new P2 (x, y), angle, font, fillStyle); 53 } 54} 55 56 57//-------------------------------- 58// canvas を使いやすいように定義 59 60class Canvas { 61 constructor (canvas) { 62 this.canvas = canvas; 63 this.ctx = canvas.getContext('2d'); 64 } 65 66 setSize (w, h) { 67 this.canvas.width = w; 68 this.canvas.height = h; 69 return this; 70 } 71 72 clear () { 73 this.canvas.width = this.canvas.width;//これは裏技的 74 } 75 76 //オブジェクトを作るときに簡単に定義できるようにするため 77 static create (target = document.querySelector ('canvas'), w = 320, h = 200) { 78 return (new Canvas (target)).setSize (w, h); 79 } 80} 81 82 83//-------------------------------- 84//マウスの位置を知るためのオブジェクト(マウス移動に連動して関数を呼び出す) 85 86class MousePointer extends P2 { 87 constructor (cbFunc, target, x, y) { 88 super (x, y); 89 this.cbFunc = cbFunc; 90 this.target = target; 91 } 92 93 //イベントハンドラー 94 handleEvent (event) { 95 const abs = Math.abs; 96 let { pageX: x, pageY: y } = event; 97 this.x = x; 98 this.y = y; 99 100 //マウスのイベントが発生するたびに登録した関数を呼び出す 101 this.cbFunc (event, new P2 (x, y)); 102 } 103 104 //オブジェクトを作りやすいように、イベントも登録 105 static create (cbFunc = null, target = document) { 106 if ('function' !== typeof cbFunc) 107 throw new Error ('Not function'); 108 109 let obj = new MousePointer (cbFunc, target); 110 target.addEventListener ('mousemove', obj, false); 111 return obj; 112 } 113} 114 115 116//-------------------------------- 117//動きをつかさどるオブジェクト 118 119class Mover { 120 constructor (canvas, elements, area, gain, target_point) { 121 this.canvas = canvas; 122 this.elements = elements; //array 123 this.aP = area;//マウスで動かす移動範囲量 124 this.gP = gain;//減速 125 this.tP = target_point;//目的地 126 127 this.cP = new P2;//現在地 128 this.aniId = null;//アニメーションID 129 } 130 131 handleEvent (event, p) { 132 this.tP = p.multi (this.aP);//目的地 = マウス座標 * 移動範囲 133 if (this.aniId) 134 this.aniId = cancelAnimationFrame (this.aniId); 135 this.draw (); 136 } 137 138 draw () { 139 let sa = this.tP.copy ().sub (this.cP).multi (this.gP);//移動距離 = (目的地:複写 - 現在地) * 減速 140 let {x, y} = this.cP.add (sa);//現在地 += 移動距離 141 142 this.canvas.clear (); 143 this.elements.forEach (t => t.draw (this.canvas, this.cP));//それぞれの文字の描画 144 145 this.aniId = (1 < x || 1 < y) 146 ? requestAnimationFrame (this.draw.bind (this)) 147 : null; 148 } 149 150 static create (canvas = Canvas.create (), elements = [], area = new P2 (.5,.5), gain = new P2 (.02, .02), init_position = new P2) { 151 return new Mover (canvas, elements, area, gain, init_position); 152 } 153 154} 155 156 157//-------------------------------- 158 159//文字をオブジェクト化し配列にする 160const TEXT = [ 161 ['a', 1144, 333, 20, '200px Fredoka One', 'rgba(88, 56, 34, 1)'], 162 ['a', 823, 427, -20, '120px Fredoka One', 'rgba(88, 56, 34, 1)'], 163 ['c', 1097, 605, 20, '120px Fredoka One', 'rgba(88, 56, 34, 1)'], 164 ['H', -118, 290, 340, '330px Fredoka One', 'rgba(88, 56, 34, 1)'], 165 ['i', 1269, 714, 20, '230px Fredoka One', 'rgba(88, 56, 34, 1)'], 166 ['M', 430, 12, 20, '240px Fredoka One', 'rgba(88, 56, 34, 1)'], 167 ['p', 1321, 656, -10, '200px Fredoka One', 'rgba(88, 56, 34, 1)'], 168 ['P', 669, 0, -25, '350px Fredoka One', 'rgba(88, 56, 34, 1)'], 169 ['P', 1074, 113, -25, '230px Fredoka One', 'rgba(88, 56, 34, 1)'], 170 ['s', 414, 496, -30, '270px Fredoka One', 'rgba(88, 56, 34, 1)'], 171 ['s', 342, 656, -20, '120px Fredoka One', 'rgba(88, 56, 34, 1)'], 172 ['T', 209, 178, -20, '150px Fredoka One', 'rgba(88, 56, 34, 1)'], 173 ['v', 927, 311, -20, '150px Fredoka One', 'rgba(88, 56, 34, 1)'] 174].map (_ => Character.create (..._) ); 175 176 177//キャンバス、ムーバーオブジェクトを作成 178const 179 canvas = Canvas.create (top_canvas, window.innerWidth, window.innerHeight), 180 demo = Mover.create (canvas, TEXT, new P2 (-.3,.3), new P2 (.02,.02)); 181 182//マウスポインターのオブジェクトを作成。ついでに動いたときに呼び出す関数を登録 183MousePointer.create (demo.handleEvent.bind (demo)); 184demo.draw ();//最初画面描画 185 186</script>

投稿2020/05/21 01:48

編集2020/05/21 01:57
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Karna554

2020/05/23 02:13

わざわざありがとうございます。 見ずらいコードですみません.... 精進します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問