Ефект блискавки на полотні canvas

ПублікаціїАнімації і ефекти
Для того щоб намалювати блискавку за допомогою JavaScript на полотні елемента canvas малюється лінія з зміщенням від прямої лінії. Саме крива лінія дозволяє додати створити ефект блискавки (електричного розяду).

Для малювання лінії у canvas використовується метод lineTo().

Найпростіший спосіб намалювати блискавку це лінія яка у випадковому порядку має зміщення вліво або право. Тобто малюємо ламану криву лінії, і від цієї лінії також малюємо інші криві лінії.

Функція Lightning приймає параметри: елемент canvas, координати полотна x і y з яких почнеться малюватися блискавка. Дочірна функція random генерує ціле випадкове число за допомогою Math.random(). Дочірна функція createLightning створює масив з координатами лінії блискавки.

<canvas id="canva1" width="400" height="400"></canvas> function Lightning(canvas,x,y){ //функція випадкового числа від min до max function random(min,max){return parseInt(Math.random()*(max-min)+min);} //функція створення блискавки function createLightning(x,y){ var res=[]; for(var i=0, sx=x, sy=y, l=random(5,30);i<l;i++){ res.push({x:sx, y:sy}); sx+=Math.random()>0.5?random(5,10):0-random(5,10); sy+=random(5,15); } return res; } var ctx=canvas.getContext('2d'); var path=[]; //створюємо першу лінії блискавки path[0]=createLightning(x,y); //створюємо інші лінії блискавки від 1 до 3 for(var i=0, j, z, l=random(1,3);i<l;i++){ j=random(0, path.length-1); z=random(0, path[j].length-1); path[path.length]=createLightning(path[j][z].x, path[j][z].y); } //очищаємо полотно canvas ctx.clearRect(0, 0, canvas.width, canvas.height); //малюємо блискавки на полотні for(var i=0; i<path.length;i++){ //ширина лінії блискавки ctx.lineWidth=path.length-i; //колір блискавки ctx.strokeStyle='#C6D4DC'; ctx.beginPath(); ctx.moveTo(path[i][0].x, path[i][0].y); for(var j=1;j<path[i].length;j++){ ctx.lineTo(path[i][j].x, path[i][j].y); } ctx.stroke(); } } //виклик функції Lightning(document.getElementById('canva1'), 150, 0);
Розглянемо функцію Lightning яка малює лінію блискавки від точки x1, y1 до x2, y2. <canvas id="canva2" width="400" height="400"></canvas> function Lightning(canvas, x1, y1, x2, y2, color){ var ctx=canvas.getContext('2d'); //очищаємо полотно canvas ctx.clearRect(0, 0, canvas.width, canvas.height); //довжина блискавки (лінії) var len=Math.max(y1,y2)-Math.min(y1,y2); //крок поділу лінії блискавки var step=2; //кількість кроків var stepCount=len/step; //максимальне зміщення px від прямої лінії блискавки var maxOffset=8; var cx=x1,cy=y1; ctx.strokeStyle=color; ctx.lineWidth=2; ctx.beginPath(); //встановлюємо початкову точку лінії ctx.moveTo(cx, cy); for(var i=stepCount;i>1;i--){ cx+=(x2-cx)/i+Math.random()*maxOffset-(maxOffset/2); cy+=(y2-cy)/i+Math.random()*maxOffset-(maxOffset/2); ctx.lineTo(cx, cy); } ctx.stroke(); } Lightning(document.getElementById('canva2'), 50, 0, 60, 350, 'blue');

Зробимо кінець лінії блискавки тоншим, а початок широким.

<canvas id="canva3" width="400" height="400"></canvas> function Lightning(canvas, x1, y1, x2, y2, color, lineWidth){ var ctx=canvas.getContext('2d'); //очищаємо полотно canvas ctx.clearRect(0, 0, canvas.width, canvas.height); //довжина блискавки (лінії) var len=Math.max(y1,y2)-Math.min(y1,y2); //крок поділу лінії блискавки var step=2; //кількість кроків var stepCount=len/step; //крок ширини лінії var steplineWidth=lineWidth/stepCount; //максимальне зміщення px від прямої лінії блискавки var maxOffset=8; var cx=x1,cy=y1; //колір блискавки ctx.strokeStyle=color; //ctx.shadowColor=color; //ctx.shadowBlur=2; ctx.lineWidth=lineWidth; for(var i=stepCount;i>1;i--){ ctx.moveTo(cx, cy); cx+=(x2-cx)/i+Math.random()*maxOffset-(maxOffset/2); cy+=(y2-cy)/i+Math.random()*maxOffset-(maxOffset/2); ctx.lineWidth-=steplineWidth; ctx.lineTo(cx, cy); ctx.stroke(); } } Lightning(document.getElementById('canva3'),100, 0, 25, 250, 'red', 4);
Реалізація ефекту блискавки з заданими початковими і кінцевими координатами, ефектом тіні. <canvas id="canvaL" width="400" height="450"></canvas> function Lightning(canvas, options){ //функція випадкового числа від min до max function random(min,max){return parseInt(Math.random()*(max-min)+min);} //параметри по замовчуванню var DEF_OPTIONS={x1: canvas.width/2, y1:0, color:'hsl(180, 80%, 80%)', lineWidth:random(1,3)}; DEF_OPTIONS.x2=random(DEF_OPTIONS.x1+50,canvas.height); DEF_OPTIONS.y2=random(DEF_OPTIONS.y1+50,canvas.height); //якщо параметр не вказано то присвоюємо параметр по замовчуванню for(var a in DEF_OPTIONS)options[a]=(a in options?options[a]:DEF_OPTIONS[a]); var ctx = canvas.getContext("2d"); //створюємо лінію блискавки var size=Math.max(options.y1, options.y2)-Math.min(options.y1, options.y2); var roughness=2; //1.8 ... 2.2 var maxDifference=size/5; var count=size; var lightning=[]; //початкові координати блискавки lightning.push({x: options.x1, y: options.y1}); //кінцеві координати блискавки lightning.push({x: options.x2, y: options.y2}); var currDiff=maxDifference; while(count>1){ var newSegments=[]; for(var i=0; i<lightning.length-1; i++){ var start=lightning[i]; var end=lightning[i+1]; var midX=(start.x+end.x)/2; var newX = midX + ((Math.random() * 2 - 1) * currDiff); newSegments.push(start, {x: newX, y: (start.y + end.y) / 2}); } newSegments.push(lightning.pop()); lightning=newSegments; currDiff=currDiff/roughness; count=count/2; } //очищаємо полотно canvas ctx.clearRect(0, 0, canvas.width, canvas.height); //малюємо лінію блискавки //колір лінії ctx.strokeStyle=options.color; //розмір лінії ctx.lineWidth=options.lineWidth; //колір тіні ctx.shadowColor=options.color; //розмір тіні ctx.shadowBlur=15; ctx.beginPath(); for(var i=0; i<lightning.length; i++){ ctx.lineTo(lightning[i].x, lightning[i].y); } ctx.stroke(); } //виклик функції Lightning(document.getElementById("canvaL"), {x1:150, y1:0, x2:155, y2:400}); Додамо можливість розгалуження блискавки, створивши додаткові лінії блискавки. function Lightning(canvas, options){ //функція випадкового числа від min до max function random(min,max){return parseInt(Math.random()*(max-min)+min);} //параметри по замовчуванню var DEF_OPTIONS={x1: canvas.width/2, y1:0, color:'hsl(180, 80%, 80%)', lineWidth:random(1,3)}; DEF_OPTIONS.x2=random(DEF_OPTIONS.x1+50,canvas.height); DEF_OPTIONS.y2=random(DEF_OPTIONS.y1+50,canvas.height); //якщо параметр не вказано то присвоюємо параметр по замовчуванню for(var a in DEF_OPTIONS)options[a]=(a in options?options[a]:DEF_OPTIONS[a]); var ctx = canvas.getContext("2d"); //функція створення лінії блискавки function createLightning(x1, y1, x2, y2){ var size=Math.max(y1, y2)-Math.min(y1, y2); var roughness=2; //1.8 ... 2.2 var maxDifference=size/5; var count=size; var lightning=[]; //початкові координати блискавки lightning.push({x: x1, y: y1}); //кінцеві координати блискавки lightning.push({x: x2, y: y2}); var currDiff=maxDifference; while(count>1){ var newSegments=[]; for(var i=0; i<lightning.length-1; i++){ var start=lightning[i]; var end=lightning[i+1]; var midX=(start.x+end.x)/2; var newX = midX + ((Math.random()*2-1)*currDiff); newSegments.push(start, {x: newX, y: (start.y + end.y) / 2}); } newSegments.push(lightning.pop()); lightning=newSegments; currDiff=currDiff/roughness; count=count/2; } return lightning; } var lightning=[]; lightning[0]=createLightning(options.x1, options.y1, options.x2, options.y2); for(var i=1, j, l=random(1,5);i<l;i++){ j=random(0, lightning[0].length-1); lightning[i]=createLightning(lightning[0][j].x, lightning[0][j].y, random(lightning[0][j].x-50, lightning[0][j].x+50), random(lightning[0][j].y+50, lightning[0][j].y+150)); } //очищаємо полотно canvas ctx.clearRect(0, 0, canvas.width, canvas.height); //малюємо лінію блискавки //колір лінії ctx.strokeStyle=options.color; //колір тіні ctx.shadowColor=options.color; //розмір тіні ctx.shadowBlur=15; for(var i=0; i<lightning.length; i++){ ctx.lineWidth=lightning.length-i; ctx.beginPath(); for(var j=0; j<lightning[i].length;j++){ ctx.lineTo(lightning[i][j].x, lightning[i][j].y); } ctx.stroke(); } } //виклик функції Lightning(document.getElementById("canvaL2"), {x1:50, y1:15, x2:155, y2:250});
Адмін 2020-01-04 18:59:26

Тільки зареєстровані користувачі можуть писати коментарі.