show

What else is there besides lanterns, fireworks and New Year animals? Certainly is snow, think about sitting on the train home, fluttering snow outside the window, the family sit together to eat dinner, flying snow, and snow are cold, as always make us feel a warm, since ancient times has a snow did good say, today is to bring together hand code with snow.

First look at the finished image, how, ok, (for GIF recording reasons, this is to put the screen is relatively small record)

implementation

First, a little background

Start with a gray background, don’t ask me why I have this background (it’s actually what MY next article will be about)

Draw a snowflake

We don’t pursue the fine degree of snowflakes too much, so we simply make a small dot to simulate snowflakes, and a white shadow to give snowflakes a hazy feeling, is there something like that?

Generate a snowflake

Snowflakes are we write die position above, just to define the shape of snowflakes first, let’s to simulate the real snow, the generation of random snowflakes, if you have seen before playing the nien beast, you will surely generate snowflakes in with sensing, yes, we first get the width of the screen, and then the generation of snow regularly, And give each snowflake a random width, note that this width should be within the width of the screen, otherwise there is no point in us going outside the screen, and wasting performance, then we give each snowflake a timer, timing to move down, and then there is.

We also use requestAnimationFrame here, but requestAnimationFrame doesn’t have a timing function, so we record the last time a snowflake was generated, compared to the current time, and if the desired interval is reached, we create the next snowflake

    lastSnowTime: ' '.// When the last snowflake was formed
    snowSpeed: 3.// The speed at which snowflakes fall
    lastSnowTime: ' '.// When the last snowflake was formed
    snowFrequency: 4.// The frequency of snowflakes

    snowStart () {
      // The frequency of snowflakes
      let now = new Date().getTime()
      if (now - this.lastSnowTime > (1000 / this.snowFrequency)) {
        
      console.log(1);
        // Create snowflake
        let snowItem = document.createElement('div')
        snowItem.className = 'snow-item'
        snowItem.style.top = -snowItem.offsetWidth + 'px'
        snowItem.style.left = Math.random() * this.screenWidth  + 'px'

        this.$refs.snowWrap.appendChild(snowItem)

        // Snowflakes move
        let snowMove = () = > {
          snowItem.style.top = snowItem.offsetTop + this.snowSpeed + 'px'
          // If the snowflake distance from the top of the screen is greater than or equal to the height of the screen, remove the snowflake
          if (snowItem.offsetTop > this.screenHeight) {
            this.$refs.snowWrap.removeChild(snowItem)
          } else {
            requestAnimationFrame(snowMove)
          }
        }

        snowMove()
        this.lastSnowTime = now
      }
      this.createSnowInterval = requestAnimationFrame(this.snowStart)
    }
Copy the code

I don’t know if it’s getting a little interesting

Optimization of snow

Although we have achieved our primary purpose, the snow always looks a little fake, why? Because nature doesn’t have such regular snow, the same size, the same speed, so we have to add more randomness to it.

The first is transparency, giving a random value to the transparency of each snowflake

snowItem.style.opacity = Math.random()
Copy the code

The second is size. We give each snowflake a random size

snowItem.snowScale = Math.random() * 0.5 + 0.5
snowItem.style.width = snowItem.offsetWidth
    * snowItem.snowScale + 'px'
snowItem.style.height = snowItem.offsetHeight
    * snowItem.snowScale + 'px'
Copy the code

So the question is, do big snowflakes fall at the same speed as small snowflakes? I haven’t really observed it closely, but it must be different, big ones fall fast, small ones fall slow? So here we have a snowflake falling speed related to its size, and as you can see, we have left a snowScale, which we’ll call the scale factor, in the random size of the snowflake, so our falling speed is proportional to the scale factor

  let moveY = this.snowSpeed * snowItem.snowScale
  snowItem.style.top = snowItem.offsetTop + moveY + 'px'
Copy the code

Here we write down the vertical offset, which will be useful later, and now to see the effect, each snowflake will have a random increase in size and speed based on the base we set. Isn’t that much better?

The snowFrequency variable is used to control the frequency at which snowflakes are generated. At first glance, it seems to be ok, but if we look at it on different devices, we will find that the larger the screen, the more sparse the snowflakes are. The smaller the screen, the more dense the snowflakes are. So the frequency we want to change with the screen, and we want to control it. Then we can set a variable, join it is 200, is a second time, every 200 pixel region generated a snowflake, so the larger the screen, a second generation of snowflakes, the screen is smaller, the generated the less snow it also don’t know why I call, let’s call this area density, we take the screen width divided by the area density, That gives us the final frequency of snowflake formation.

  snowFrequencyRatio: 300.// The larger the snowflake frequency coefficient, the fewer the snowflake
  mounted () {
    // Calculate the frequency of snowflake generation based on the snowflake frequency coefficient and screen width
    this.snowFrequency = Math.floor(this.screenWidth
        / this.snowFrequencyRatio)
    this.createCity()
    this.snowStart()
  },
Copy the code

To some wind

Since it is a fluttering snowflake, it is not interesting to fall vertically all the time, why don’t we come to some wind, let it float up.

Thinking analysis, since the incoming wind, that is certainly to let the snowflake lateral movement, that move how much? We started to snow falling speed gave it to a fixed value, according to this idea, we give the snowflakes transverse offset to a fixed value must be no problem, but now the question is the basis and we snowflakes falling speed is falling speed, its size, we will set a horizontal offset distance, let, it also has something to do with the size of this is too much trouble, And this value is set up at our discretion, too lax.

So do you have any good ideas? Ha, ha, ha, here we imagine the appearance of the snowflakes falling (not consider dancing snowflakes curve), consider the relationship between the vertical and horizontal offset offset, isn’t it a Rt delta (is part of the students with poor grades students have forgotten what is this, that’s right, this is a right triangle)

Here Angle α is the offset we set, a is the vertical displacement, we already know both of those, so using the tangent formula, tanα = b/a, we can easily calculate the value of B, which is the value of the horizontal offset, in js we can use the method math.tan to do that, The Math. Tan method accepts a radian value, and the conversion formula between Angle and radian is


radian = The Angle M a t h . P I / 180 Radians = Degrees * math.pi / 180

So here our lateral offset is going to be

let moveX = Math.tan(this.snowAngle * Math.PI / 180) * moveY
snowItem.style.left = snowItem.offsetLeft - moveX + 'px'
Copy the code

In this way, the effect of horizontal movement of snowflakes comes out (students with excellent grades are not very simple, students with poor grades I looked at tangents for a long time before I was confused).

It looks nice, but here’s the thing, if you’re careful, there’s always no snow in the bottom right hand corner, and that’s because the snow is now moving like this

The snowflake that we create on the far right of the screen, when it hits the ground, it’s not going to be on the far right of the screen, it’s going to be offset by one b, so how do we solve this problem, which is when the snowflake is created, we take the distance of this B into account, like this

So how do we solve for this b? It’s actually the same way that we figure out how far the snowflake moves, except that a is the height of the screen, so the random distance that we give to the snowflake is going to look something like this

// When assigning random horizontal coordinates to snowflakes, the range should also take into account the offset of the snowflake, otherwise the bottom right corner of the screen will be blank
let _left = (this.screenWidth + Math.tan(this.snowAngle * 
Math.PI / 180) * this.screenHeight) * Math.random()
snowItem.style.left = _left  + 'px'
Copy the code

This will not be a problem, but there will be a certain performance problem, that is, we will generate a lot more snowflakes, just like in the picture, although we can’t see the snowflakes in the orange area, they are moving and consuming performance. The more snowflakes there are at the same time, the more serious the performance loss will be

I don’t know how to optimize the snowflake on the right, but for the one on the left, we can add a judgment to remove the snowflake when it exceeds the screen on the left.

// If the snowflake offset Angle is greater than 0, determine whether the snowflake exceeds the left screen
  if (this.snowAngle > 0) {
    if (snowItem.offsetLeft < (-snowItem.offsetWidth)) {
      this.$refs.snowWrap.removeChild(snowItem)
      return}}Copy the code

Well, this article is over here, the corresponding complete code will be posted in my next article when the birth of oh (I hope to be able to have a natural birth), my low level of education, limited technology, if you have any suggestions or corrections, welcome to the comment area message