How to create city and breathe life into it with SVG and CSS3 Animations
Top

City of Animation

Animations give the web-page some liveliness and if they are high-quality animations, you won’t want to leave the page! Animations are the future, constantly developing, making them a staple in web-development.

For that reason we’ve created “Sin City”, a web-page filled with animations which respond to the actions of users. The view of the city has many shifting details, so we chose a template which you’ll notice on the right hand side.
In order to bring this city to life, you’ll need to know a little JavaScript. 🙂

First, we need to set up the following tasks:

  1. Permanent animations:
    • Ferris wheel rotation
    • Clouds floating across the sky which hide as the sun sets
  2. On scroll:
    • The cars drive at different speeds. When a car arrives at the edge of the screen it shows the opposite side of the screen and the wheels rotate.
    • The sun gradually hides behind the horizon.
    • The sky gradually darkens and the moon becomes visible in the sky.
    • The shadows on the building should appear as the sun sets.
    • When the sun sets, windows of the buildings light up and headlights come on.
    • When traffic lights flash green, cars move, and when they flash red, cars stop.

The next step was to create a project structure. We decided that it will look like this:

  • /images – directory for images;
  • /js – directory for our scripts;
  • /scss – directory for our styles.

Also, the index.html is located in the root directory.

Process Of Development

Let’s discuss the development process. First, we need to save all elements as SVG-images. Also, we need save the wheels of the cars separately from the car because they will rotate separately from the car. The same should be done with the cabins of the ferris wheel.

Constant animations are done with the help of CSS3 (keyframes), for example, the cloud animations (each cloud in the sky has a unique rule).

@for $i from 1 through 5 {
    &.cloud#{$i}{
        animation: cloud#{$i} random(100) + 50 + s infinite;
    }
    @keyframes cloud#{$i} {
        0% {
            transform: translateX(random(100) + %);
            opacity: 0;
        }
        15% {
            opacity: 1;
        }
        100% {
            transform: translateX(random(100) + %);
            opacity: 0;
        }
    }
}

Let’s move on to the code that make JS-magic 🙂

Initially, I wrote the code with the help of jQuery and didn’t use a prototype but the code turned out flawed and poorly supported. That’s when we decided to fix the code to OOP and used classes and prototypes.

The car animation requires us to create a class Car
For animation of the cars we need create class Car (in file /js/modules/animations-car.js):

function Car(selector, screenWidth){
    this.elem = selector;
    this.speed = this.elem.getAttribute('data-speed');
    this.direction = this.elem.getAttribute('data-direction');
    this.wheels = this.elem.querySelectorAll('.img-wheel');
    this.wheelDeg = 0;
    this.flag = false;
    this.DIRECT_LEFT = 'left';
    this.DIRECT_RIGHT = 'right';
    this.curPos = 0;
    this.carWidth = this.elem.clientWidth;
    this.screenWidth = screenWidth;

    this.carInit();
}

Let’s see what this code means.

this.speed = this.elem.getAttribute('data-speed');
this.direction = this.elem.getAttribute('data-direction');

Here the attributes ‘data-speed’ and ‘data-direction’ will define the speed of the car and the direction at which it drives respectively. We get it from the HTML of each car:

<div class="car-wrap car5" data-speed="160" data-direction="left">
     <img src="assets/images/car5.svg" class="img-car" alt="image description">
     <img src="assets/images/wheel5.svg" class="img-wheel first" alt="image description">
     <img src="assets/images/wheel5.svg" class="img-wheel second" alt="image description">
</div>

The function this.carInit(); initializes the function drive() on the event ‘wheel’ and if the user uses a mobile device it calls the function driveMobile():

Car.prototype.carInit = function(){
    var self = this;
    if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
        self.driveMobile.call(self);
    }
    document.body.addEventListener('wheel', $.throttle(250, true, self.drive.bind(self)));
    document.body.addEventListener('keyup', $.throttle(250, true, self.keyHandler.bind(self)));
    window.addEventListener('resize', function(){
        self.carWidth = self.elem.clientWidth;
        self.screenWidth = document.documentElement.clientWidth;
    });
    };

The function drive() in its turn calls the function wheelFunc() (depending on the direction of your scroll):

Car.prototype.drive = function(e){
    var self = this,
    delta = e.deltaY || e.originalEvent.wheelDelta || e.wheelDelta,
    deltaMouseWheelPlus = 1,
    deltaMouseWheelMinus = -1;

    if(self.flag){
        return;
    }
    if(delta > 0){
        self.wheelDeg += 75;
        self.wheelFunc(deltaMouseWheelMinus);
        
    } else {
        self.wheelDeg -= 75;
        self.wheelFunc(deltaMouseWheelPlus);

    }
};

The function wheelFunc() do the following:

  • Cars move accordingly when you scroll using the mouse wheel
  • Rotates the wheels of the car from one side to the other

The next step in our project was the animation of the heavenly bodies and to change the time of day. The animation of the sun and the moon we described in file:/js/modules/animations-sun.js.
The sun and the moon move in the sky. When one of them reaches the edge of the screen, the other one will become visible and will alternate from day to night conversely. When the moon is visible in the sky, car headlights turn on and the windows in the buildings also lights up.

Responsive

We want our web-page to look impeccable not only on desktop but on all devices, so let’s focus on the events that don’t work on mobile devices. On mobile devices, there is a missing event ‘wheel’ , instead of this event we use ‘touchstart’ and ‘touchend’:

document.body.addEventListener('touchstart', function(e){
     touchstartY = e.changedTouches[0].screenY;
});
document.body.addEventListener('touchend', function(e){
     touchendY = e.changedTouches[0].screenY;
     if (touchendY < touchstartY) {
          self.wheelDeg += 75;
          self.wheelFunc(deltaMouseWheelMinus);
         
     } else if (touchendY > touchstartY) {
          self.wheelDeg -= 75;
          self.wheelFunc(deltaMouseWheelPlus);
     }
});

As screens of the mobile devices have small dimensions we decided to hide most parts of the cars, the buildings, and the ferris wheel.

Troubleshooting

What kind of development does not have bugs 🙂 During development, there was trouble in Safari with the moving cars and moon. In order to determine the position of the cars, we use the method getComputedStyle, but in different browsers it returns different values for the left position (it appears if we use a percent for the style of position). In order to fix this, we use the method getBoundingClientRect().left instead.

Easter Eggs

We’ve created a few surprises for our website visitors:

  1. Double click on the cabin of the ferris wheel and the cabin will fall down.
  2. Press on the space and all the cabins on the ferris wheel will fall down
  3. Double click on the DBC banner and it will fall down while a plane flies across the sky.

Conclusion

So let’s sum up the main moments of this project. First, the best way is to use the principles OOP, classes, and prototypes in the JavaScript code.
Second, do not forget that mobile devices are missing the event ‘wheel’, and instead the events ‘touchstart’ and ‘touchend’ should be used. Finally, to determine the position of the element, it’s recommended to use the getBoundingClientRect().left method because the method getComputedStyle returns different values for the left position in different browsers (if it’s defined by a percent but the real trouble was in the use of pixels for the style of the position).

Don’t forget to visit “Sin City” and also check out GitHub

up

Please turn your device