Я нашел этот отличный сценарий, чтобы сделать его дождевой конфетти: http://jsfiddle.net/hcxabsgh/ Обратите внимание, как частицы имеют этот эффект твист/поворот/перекос, чтобы сделать его более естественным.
Я пытаюсь сделать частицы вокруг, которые также хорошо работают: http://jsfiddle.net/rqr9hb7x/2/
Но я не могу заставить частицы крутить/поворачивать/перекоса вокруг своих осей, как в прямоугольном примере.
Я решил, что это должно выполняться с помощью ctx.setTransform(), поскольку он обрабатывает косые параметры, но, похоже, он искажает весь холст вместо одиночной частицы. Кто-нибудь знает, как правильно подойти?
this.draw = function () {
ctx.beginPath();
ctx.save();
//ctx.setTransform(1, 0, 0, 1, 0, 0); // straigt
ctx.setTransform(1, .3, 0, .7, 0, 0); // skewed - to make dynamic
ctx.arc(this.x + this.tilt, this.y + this.tilt + (this.r / 4), (this.r / 2), 0, Math.PI * 2, false);
ctx.restore();
ctx.fillStyle = this.color;
return ctx.fill();
}
setTransform
с использованием setTransform
Вы хотите вращать локальную ось x частиц с течением времени. Ось x - это первые два аргумента setTransform
. Чтобы повернуть эту ось с течением времени, вы используете cos(angle)
и sin(angle)
для установки x и y-составляющей оси x.
Поскольку вы хотите, чтобы это было локально для частицы, вам нужно также установить начало частицы (точку вращения), а затем нарисуйте частицу на 0,0. Происхождение - это два последних аргумента setTransform
Функция розыгрыша, которую вы хотите,
draw() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.setTransform(
Math.cos(this.tiltAngle), // set the x axis to the tilt angle
Math.sin(this.tiltAngle),
0, 1,
this.x, this.y // set the origin
);
ctx.arc(0, 0, (this.r / 2), 0, Math.PI * 2, false); // draw at origin (0,0)
ctx.fill();
}
Глядя на код на скрипке, я не мог понять, что они пытались сделать, поскольку это было слишком сложно, поэтому я переписал все, что теперь занимает 3-й код и не jQuery.
Запустите демо для FX, который вы после...
может быть????
(function () {
requestAnimationFrame(mainLoop);
const ctx = canvas.getContext("2d");
var W,H;
var confetti = new Particles();
var droppedCount = 0;
var particlesPerFrame = 1.5;
var wind = 0;
var windSpeed = 1;
const windSpeedMax = 1;
const windChange = 0.01;
const windPosCoef = 0.002;
const maxParticlesPerFrame = 2; //max particles dropped per frame
var id = 0;
stopButton.addEventListener("click",() => particlesPerFrame = 0 );
startButton.addEventListener("click",() => particlesPerFrame = maxParticlesPerFrame);
const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
const rand = (min = 1, max = min + (min = 0)) => Math.random() * (max - min) + min;
const colors = {
options: "DodgerBlue,OliveDrab,Gold,pink,SlateBlue,lightblue,Violet,PaleGreen,SteelBlue,SandyBrown,Chocolate,Crimson".split(","),
index: 0,
step: 10,
get color() { return colors.options[((colors.index++) / colors.step | 0) % colors.options.length] }
}
function Confetti() { this.setup() }
Confetti.prototype = {
setup(){
this.x = rand(-35,W + 35);
this.y = rand(-30,-35);
this.r = rand(10, 30);
this.d = rand(150) + 10; //density;
this.color = colors.color;
this.tilt = randI(10);
this.tiltAngleIncremental = (rand(0.08) + 0.04) * (rand() < 0.5 ? -1 : 1);
this.tiltAngle = 0;
this.angle = rand(Math.PI * 2);
this.id = id++;
return this;
},
update() {
this.tiltAngle += this.tiltAngleIncremental * (Math.cos(wind + (this.d + this.x + this.y) * windPosCoef) * 0.2 + 1);
this.y += (Math.cos(this.angle + this.d) + 3 + this.r / 2) / 2;
this.x += Math.sin(this.angle);
this.x += Math.cos(wind + (this.d + this.x + this.y) * windPosCoef) * windSpeedMax;
this.y += Math.sin(wind + (this.d + this.x + this.y) * windPosCoef) * windSpeedMax;
this.tilt = (Math.sin(this.tiltAngle - (this.id / 3))) * 15;
return this.y > H; // returns true if particle is past bottom
},
draw() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.setTransform(
Math.cos(this.tiltAngle), // set the x axis to the tilt angle
Math.sin(this.tiltAngle),
0, 1,
this.x, this.y // set the origin
);
ctx.arc(0, 0, (this.r / 2), 0, Math.PI * 2, false);
ctx.fill();
}
}
function Particles() {
const items = [];
const pool = [];
this.update = function() {
for (var i = 0; i < items.length; i++) {
if(items[i].update() === true){ pool.push(items.splice(i--,1)[0]) }
}
}
this.draw = function() { for (var i = 0; i < items.length; i++) { items[i].draw() } }
this.add = function() {
if (pool.length > 0) { items.push(pool.pop().setup()) }
else { items.push(new Confetti()) }
}
}
function mainLoop(time) {
if (W !== innerWidth || H !== innerHeight) {
W = canvas.width = innerWidth;
H = canvas.height = innerHeight;
} else {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, W, H);
}
windSpeed = Math.sin(time / 8000) * windSpeedMax;
wind += windChange;
while(droppedCount < particlesPerFrame){
droppedCount += 1;
confetti.add();
}
droppedCount -= particlesPerFrame;
confetti.update();
confetti.draw();
requestAnimationFrame(mainLoop);
}
})();
* {
margin: 0;
padding: 0;
}
body {
/*You can use any kind of background here.*/
background: transparent;
}
canvas {
display: block;
position: relative;
zindex: 1;
pointer-events: none;
}
#content {
text-align: center;
width: 500px;
height: 300px;
position: absolute;
top: 50%;
left: 50%;
margin-left: -250px;
margin-top: -150px;
color: silver;
font-family: verdana;
font-size: 45px;
font-weight: bold;
}
.buttonContainer {
display: inline-block;
}
button {
padding: 5px 10px;
font-size: 20px;
}
<div id="content">
Confetti World
<br /> I confetti!
<br />
<div class="buttonContainer">
<button id="stopButton">Stop Confetti</button>
<button id="startButton">Drop Confetti</button>
</div>
</div>
<canvas id="canvas"></canvas>
Примечание. Некоторые из этого кода и содержимого были скопированы из этого скрипта.
ctx.setTransform(1, .3, 0, .7, 0, 0);
x
иy
вctx.setTransform(1, .3, 0, .7, 0, 0);