Skin:
[NORMAL]
[BLUE] [DOS] [LIGHT]  / コピーするための表示 / 実行
このファイル: /home/web6047/www/cgi-bin/prj/20200705-indexJS/index.js
1
2 class App {
3 constructor( canvasId, dir ) {
4 this.dir = dir;
5 this.cc = document.getElementById( canvasId ).getContext( "2d", { alpha : false } );
6
7 this.parentElement = this.cc.canvas.parentNode;
8 console.log( this.parentElement.tagName );
9 this.parentElement.style.position = "relative";
10 this.cc.canvas.style.position = "absolute";
11 this.cc.canvas.style.left = "0px";
12 this.cc.canvas.style.top = "0px";
13 this.cc.canvas.style.imageRendering = "crisp-edges";
14
15 this.aspect = this.cc.canvas.height / this.cc.canvas.width;
16 this.cc.canvasWidth = this.cc.canvas.width;
17 this.cc.canvasHeight = this.cc.canvas.height;
18
19 if( 0 ) { //レトロ風にする
20 //ドットの粗さ
21 this.pxW = 1;
22 this.pxH = 2;
23
24 //解像度を下げる
25 this.cc.canvas.width /= this.pxW;
26 this.cc.canvas.height /= this.pxH;
27
28 //解像度1ピクセル当たりのピクセル数を変更
29 this.cc.scale( 1 / this.pxW, 1 / this.pxH );
30
31 /*
32 以降、this.cc.canvas.width と this.cc.canvas.height を参照している部分は、
33 this.cc.canvasWidth と this.cc.canvasHeight に変更してください。
34 */
35 }
36
37 let onresizex = function( e ) {
38 //canvasのサイズ
39 let pr = this.parentElement.getBoundingClientRect();
40 this.cc.canvas.style.width = pr.width + "px";
41 this.cc.canvas.style.height = this.aspect * pr.width + "px";
42 this.parentElement.style.height = this.aspect * pr.width + "px";
43
44 let test = document.getElementById( "whiteareaId" );
45 if( test ) {
46 test.style.paddingTop = this.aspect * pr.width + "px";
47 }
48 }
49 addEventListener( "resize", onresizex.bind( this ) );
50 onresizex.call( this );
51
52 this.bcc = document.createElement( "canvas" ).getContext( "2d" );
53 this.bcc.canvas.width = this.cc.canvasWidth;
54 this.bcc.canvas.height = this.cc.canvasHeight;
55 if( 0 ) { //bccが何を描いているか
56 document.body.appendChild( this.bcc.canvas );
57 }
58 this.phase = "loading";
59 this.anms = new Array();
60
61
62 this.starColors = [
63 "white",
64 ];
65 this.starTimes = [ //上から下まで何秒かかるか (ms)
66 1500, 3000
67 ];
68
69 this.timerMs = 70;
70 // this.timerId = setInterval( this.frame.bind( this ), this.timerMs );
71
72 //---スクロール停止対応2 ここから
73
74 //どの要素を対象にしますか
75 this.target = this.cc.canvas;
76
77 //要素が何%見えたらアクティブにしますか
78 this.targetPer = 0.5;
79
80 this.isActive = false;
81 addEventListener( "scroll", this.onscrollx.bind( this ) );
82
83 this.onscrollx();
84
85 //---スクロール停止対応2 ここまで
86
87
88 this.execute();
89
90 }
91 //App
92
93
94 //App
95 async execute() {
96
97 //背景の星のオブジェクトを 50 個生成
98
99 this.stars = new Array();
100 for( let i = 0; i < 50; i++ ) {
101 let star = {
102 x : Math.random() * this.cc.canvasWidth,
103 y : Math.random() * this.cc.canvasHeight,
104 color : this.starColors[ Math.floor( Math.random() * this.starColors.length ) ],
105 }
106 let starTime = this.starTimes[ Math.floor( Math.random() * this.starTimes.length ) ];
107 let a = 2.5; //星の流れの傾斜 (x=1に対するyの割合)
108 let len = Math.sqrt( Math.pow( this.cc.canvasHeight, 2 ) + Math.pow( this.cc.canvasHeight / a, 2 ) );
109 let add = len / ( starTime / this.timerMs ); //1timer当たりどれくらい星は流れるか
110 star.addX = Math.sqrt( add * add * ( 1 * 1 ) / ( 1 + a * a ) ); //そのx成分
111 star.addY = Math.sqrt( add * add * ( a * a ) / ( 1 + a * a ) ); //そのy成分
112 this.stars.push( star );
113 }
114
115
116 //前景 画像のプリロード
117
118 let image;
119
120 image = await this.loadImage( this.dir + "text1.png" );
121 this.text1 = new TestImage( image, 550, this.bcc );
122
123 image = await this.loadImage( this.dir + "text2.png" );
124 this.text2 = new TestImage( image, 550, this.bcc );
125
126 image = await this.loadImage( this.dir + "title.png" );
127 this.title = new TestImage( image, 640, this.bcc );
128
129 image = await this.loadImage( this.dir + "back.png" );
130 this.back = new TestImage( image, 550, this.bcc );
131 this.back.adjustX = 0;
132 this.back.adjustY = - 35;
133
134 this.elements = new Array();
135 this.elements.push( this.text1 );
136 this.elements.push( this.text2 );
137 this.elements.push( this.back );
138 this.elements.push( this.title );
139
140 //各種アニメを順次実行
141
142 let dev = 1; //基本1。デバッグ時は0.1などにすれば表示要素の切り替えを早められる。
143 let ms = 1000; //基本1000。デバッグ時は2000などにすれば画面効果をゆっくり見られる。 ※A
144 let text = true;
145 let leave = true;
146
147 while( 1 ) {
148
149 this.anms = new Array();
150 if( text ) {
151 //最初のテキスト
152 await this.fadeImage( this.text1, "transparent", "blue", ms );
153 await this.fadeImage( this.text1, "blue", "normal", ms );
154 await this.delay( 9000 * dev );
155 await this.fadeImage( this.text1, "normal","blue", ms );
156 await this.fadeImage( this.text1, "blue","transparent", ms );
157 await this.delay( 1500 * dev );
158
159 //次のテキスト
160 this.text1.visibility = false;
161 await this.fadeImage( this.text2, "transparent","blue", ms );
162 await this.fadeImage( this.text2, "blue","normal", ms );
163 await this.delay( 12000 * dev );
164 await this.fadeImage( this.text2, "normal","blue", ms );
165 await this.fadeImage( this.text2, "blue","transparent", ms );
166 await this.delay( 500 * dev );
167 }
168
169 //ロゴ
170 this.text2.visibility = false;
171 await this.fadeImage( this.title, "transparent","blue", ms );
172 await this.fadeImage( this.title, "blue","little", ms );
173 await this.fadeImage( this.title, "little","normal", ms * 1.5 );
174
175 //魔法陣
176 await this.fadeImage( this.back, "transparent","blue", ms );
177 await this.fadeImage( this.back, "blue","little", ms );
178 await this.fadeImage( this.back, "little","normal", ms );
179
180 await this.delay( 18000 * dev ); //ここで画面完成
181
182 if( leave ) {
183 //消す
184 await this.fadeImage( this.back, "normal","blue", ms / 3 );
185 await this.fadeImage( this.back, "blue","transparent", ms / 3 );
186 await this.fadeImage( this.title, "normal","blue", ms / 3 );
187 await this.fadeImage( this.title, "blue","transparent", ms / 3 );
188 }
189
190 await this.delay( 2000 * dev );
191
192 this.text1.visibility = true;
193 this.text2.visibility = true;
194 this.back.visibility = true;
195
196 }
197
198 this.phase = "";
199
200 }
201
202 //App
203 fadeImage( testimage, beforeMode, afterMode, ms ) {
204 return new Promise(
205 function( tellOk ) {
206 testimage.beforeMode = beforeMode;
207 testimage.afterMode = afterMode;
208 let anm = {
209 stavalue : 0,
210 endvalue : testimage.spanbordermax,
211 addvalue : null,
212 nowvalue : null,
213 object : testimage,
214 member : "spanborder",
215 tellOk : tellOk,
216 }
217 anm.addvalue = ( anm.endvalue - anm.stavalue ) / ( ms / this.timerMs );
218 anm.nowvalue = 0;
219 this.anms.push( anm );
220
221 this.phase = "test";
222 }.bind( this )
223 );
224 }
225
226 //App
227 frame() {
228
229 //背景の星 値を動かす
230
231 for( let i = 0; i < this.stars.length; i++ ) {
232 let star = this.stars[ i ];
233 star.x += star.addX;
234 star.y += star.addY;
235 //check. 画面外に出たか?
236 if( star.x > this.cc.canvasWidth || star.y > this.cc.canvasHeight ) {
237 //位置を上部へ移動
238 let v1 = this.cc.canvasWidth + this.cc.canvasHeight;
239 let v2 = Math.random() * v1;
240 if( v2 < this.cc.canvasWidth ) {
241 //画面上部から再出発
242 star.x = v2;
243 star.y = 0;
244 } else {
245 //画面左端から再出発
246 star.x = 0;
247 star.y = v2 - this.cc.canvasWidth;
248 }
249 }
250 }
251
252 //前景 汎用的なアニメ処理
253
254 for( let i = 0; i < this.anms.length; i++ ) {
255 let anm = this.anms[ i ];
256 anm.nowvalue += anm.addvalue;
257 anm.object[ anm.member ] = anm.nowvalue;
258 //check.
259 if( anm.addvalue > 0 && anm.nowvalue >= anm.endvalue ||
260 anm.addvalue < 0 && anm.nowvalue <= anm.endvalue ) {
261 anm.tellOk();
262 }
263 }
264
265 this.draw( this.cc );
266 }
267 //App
268 draw( cc ) {
269 cc.clearRect( 0, 0, cc.canvasWidth, cc.canvasHeight );
270
271 //背景の星 描画
272
273 for( let i = 0; i < this.stars.length; i++ ) {
274 let star = this.stars[ i ];
275 cc.fillStyle = star.color;
276 cc.fillRect( star.x, star.y, 1, 2 );
277 }
278
279 //前景 描画
280
281 switch( this.phase ) {
282 case "loading":
283 cc.fillText( "Loading..", 100, 100 );
284 break;
285
286 case "test":
287 cc.fillStyle = "green";
288
289 for( let i = 0; i < this.elements.length; i++ ) {
290 let element = this.elements[ i ];
291 element.draw( cc );
292 }
293 break;
294 }
295 }
296
297 //---utl
298
299 //App
300 delay( ms ) {
301 return new Promise(
302 function( tellOk ) {
303 setTimeout( tellOk, ms );
304 }
305 );
306 }
307
308 //App
309 loadImage( src ) {
310 let image;
311 return new Promise(
312 function( tellOk ) {
313 image = new Image();
314 image.onload = tellOk;
315 image.src = src;
316 }.bind( this )
317 ).then(
318 function() {
319 console.log( src + " loaded." );
320 return image;
321 }.bind( this )
322 );
323 }
324
325 //---スクロール停止対応1 ここから
326
327 start() {
328 this.timerId = setInterval( this.frame.bind( this ), this.timerMs );
329 }
330 stop() {
331 clearInterval( this.timerId );
332 }
333 onscrollx( e ) {
334 var rect = this.target.getBoundingClientRect();
335 var targetTopP = ( rect.top ) + ( rect.height * this.targetPer );
336 var targetBottomP = ( rect.top + rect.height ) - ( rect.height * this.targetPer );
337 var windowTop = 0;
338 var windowBottom = window.innerHeight;
339 var overTheTop = targetBottomP < windowTop; //ウィンドウ上方へ隠れた
340 var overTheBottom = targetTopP > windowBottom; //ウィンドウ下方へ隠れた
341 var isVisible = ! overTheTop && ! overTheBottom;
342 if( ! this.isActive && isVisible ) {
343 this.isActive = true;
344 this.start();
345 } else if( this.isActive && ! isVisible ) {
346 this.isActive = false;
347 this.stop();
348 }
349 }
350
351 //---スクロール停止対応1 ここまで
352
353
354 }//App
355
356 class TestImage {
357 constructor( image, width, bcc ) {
358 this.image = image;
359 let height = width / image.width * image.height;
360 this.bcc = bcc; //あとでまた使う
361 //image を imageData に変換する(bccに描画してgetする)
362 bcc.clearRect( 0, 0, bcc.canvas.width, bcc.canvas.height );
363 bcc.drawImage( image, 0, 0, width, height );
364 this.imagedata = bcc.getImageData( 0, 0, width, height );
365 this.x = 0;
366 this.y = 0;
367 this.adjustX = 0;
368 this.adjustY = 0;
369 this.spanbordermax = 47; //span border max
370 this.spanborder = 0; //0:alldraw ~ max:alloff
371 this.visibility = true;
372
373 this.modes = {
374 normal : { r : 1, g : 1, b : 1, a : 1 }, //通常
375 little : { r : 0.6, g : 0.6, b : 0.6, a : 1 }, //明るさ半分
376 transparent : null, //透明
377 blue : { r : 0, g : 0, b : 1, a : 1 }, //ブルー
378 }
379
380 }
381 //TestImage
382 draw( cc ) {
383 //check.
384 if( ! this.visibility ) return;
385 let imagedata2;
386
387 let before = this.modes[ this.beforeMode ];
388 let after = this.modes[ this.afterMode ];
389 /*
390 1枚の画像は「さざなみ」のように2つの描画モードが混在される。
391 this.spanbordermaxピクセルの内、左側がafterで、右側がbefore。
392 this.spanborderの値が0からthis.spanbordermaxまでアニメにより変化する。
393 その結果、this.spanbordermaxピクセル中のafterとbeforeの比率が変わるので、
394 全beforeの状態から全afterの状態へだんだん移り変わる、さざなみアニメとなる。
395
396 たとえば、this.spanbordermaxが18ドットで、this.spanborderが0だと、ドットはすべてbeforeのモードで描かれる。
397 this.spanborderが9だと、beforeとafterが半々。
398 this.spanborderが18だと、すべてafterのモードで描かれる。
399 たとえば、青一色から明るい色へとさざなみのように移り変わる。
400 */
401
402 imagedata2 = cc.createImageData( this.imagedata );
403
404 for( let y = 0; y < this.imagedata.height; y ++ ) {
405 for( let x = 0; x < this.imagedata.width; x ++ ) {
406 let seek = y * this.imagedata.width * 4 + x * 4;
407
408 //元の画像の1ドット
409 let r = this.imagedata.data[ seek ];
410 let g = this.imagedata.data[ seek + 1 ];
411 let b = this.imagedata.data[ seek + 2 ];
412 let a = this.imagedata.data[ seek + 3 ];
413
414 let isAfter = ( y * this.imagedata.width + x ) % this.spanbordermax < this.spanborder;
415
416 let thismode = isAfter ? after : before;
417 //check. (transparent)
418 if( thismode == null ) continue;
419
420 //加工後
421 imagedata2.data[ seek ] = r * thismode.r;
422 imagedata2.data[ seek + 1 ] = g * thismode.g;
423 imagedata2.data[ seek + 2 ] = b * thismode.b;
424 imagedata2.data[ seek + 3 ] = a * thismode.a;
425 }
426 }
427
428 //加工後のimagedataを画面に描画
429 //imagedataはそのままputImageすると、他の画像との重ね合わせができない(canvasの仕様)ので、
430 //bccに描画してからbcc.canvasをccへdrawImageする。(すると他の画像との重ね合わせができる)
431 this.bcc.clearRect( 0, 0, this.bcc.canvas.width, this.bcc.canvas.height );
432 this.bcc.putImageData( imagedata2, 0, 0 );
433 this.x = ( cc.canvasWidth - this.imagedata.width ) / 2; //センタリング
434 this.y = ( cc.canvasHeight - this.imagedata.height ) / 2;
435 this.x += this.adjustX;
436 this.y += this.adjustY;
437 cc.drawImage( this.bcc.canvas, this.x, this.y );
438 }
439
440 }//TestImage