geek man
geek man

Reputation: 309

how to implement 3d slider in angular 10

I am pretty new to angular and I want to create a 3d carousel slider like this in angular. How can I approach this problem? please see the link for better presentation of the problem

function rotateLeft(){
  if(on == 0){
    $('.p_slider__item:nth-of-type(' + pos + ')').animate({'left':'200px'},200)
    $('.p_slider__item:nth-of-type(' + pos + ')').css('z-index','0')
    $('.p_slider__item:nth-of-type(' + pos2 + ')').animate({'left':'-200px'},200)
    setTimeout (function(){
      $('.p_slider__item:nth-of-type(' + pos2 + ')').css({'transform':'scale(0.6)','opacity':'0.8','webkit-filter':'blur(2px)','z-index':'1'});
      pos++;pos2++;pos3++;
      if(pos > 3){pos = 1}if(pos2 > 3){pos2 = 1;}if(pos3 > 3){pos3 = 1;}
    },400)
    $('.p_slider__item:nth-of-type(' + pos3 + ')').animate({'left':'0px'},200)
    $('.p_slider__item:nth-of-type(' + pos3 + ')').css({'transform':'scale(1)','opacity':'1','webkit-filter':'blur(0px)','z-index':'2'})
    setTimeout (function(){
      on = 0; // Accept clicks again
    },time)
  }
}

Upvotes: 0

Views: 2813

Answers (3)

Eliseo
Eliseo

Reputation: 57939

google is our friend, in this David DeSandro's article you has all the "ingredients". Yes is css and javascript but you can easy translate to Angular

To get the cells we use viewChild and ViewChildren

  @ViewChild('carousel') carousel:ElementRef
  @ViewChildren('carousel__cell') cells:QueryList<ElementRef>

We need some auxiliars variables:

  selectedIndex = 0;
  cellWidth:number;
  cellHeight:number;
  isHorizontal:boolean = true;
  rotateFn = this.isHorizontal ? 'rotateY' : 'rotateX';
  radius:number
  theta:number;

  get cellCount()
  {
    return this.cells.length;
  }

Now create a function initCarousel

  initCarousel() {
    this.theta = 360 / this.cellCount;
    const cellSize = this.isHorizontal ? this.cellWidth : this.cellHeight;
    this.radius = Math.round( ( cellSize / 2) / Math.tan( Math.PI / this.cellCount ) );
    this.cells.forEach((cell:ElementRef,i:number)=>
    {
       if (i<this.cellCount)
       {
           cell.nativeElement.style.opacity=1
           const cellAngle=this.theta*i;
           cell.nativeElement.style.transform = this.rotateFn + '(' + cellAngle + 'deg) translateZ(' + this.radius + 'px)';
       }
       else
       {
        cell.nativeElement.style.opacity = 0;
        cell.nativeElement.style.transform = 'none';

       }
    })
    this.rotateCarousel();
  }

That we call in ngAfterViewInit

  ngAfterViewInit()
  {
    this.cellWidth = this.carousel.nativeElement.offsetWidth;
    this.cellHeight = this.carousel.nativeElement.offsetHeight;
    this.initCarousel()
  }

You can see in stackblitz

Updated Really the question is about a "pseudo-3d" and it's more easy. We need applied transform a scale and a position, so, we can has a function like

  getStyle(index:number)
  {
    if (!this.cellCount)
       return null;
    const angle=(index-this.selectedIndex)*2*Math.PI/this.cellCount
    const scale=((75)+25*Math.cos(angle))/100
    return {
      left:-75+150*Math.sin(angle)+'px',
      transform:'scale('+scale+')',
      position:'absolute',
      "z-index":Math.floor(100*scale)
    }
  }

And apply to a carousel

<div class="carousel" style="position:relative">
  <div *ngFor="let i of [0,1,2,3,4,5,6]" class="carousel__cell" 
     [ngStyle]="getStyle(i)">{{i}}
  </div>
</div>

Update 2 using Angular animations. Well the last carousel it's looks like we want to achieve. For a particular case we can, e.g. has 9 positions defined and 3 images in position 0,2 and 7

in constructor inject AnimationBuilder

  constructor(private builder: AnimationBuilder) {}

And define as variables

  private player: AnimationPlayer;
  timer = 1000;
  animates = [0, 2, 7];

We define an auxiliar variable

  movements = [
    { pos: 0, right: [1, 2], left: [8, 7] },
    { pos: 2, right: [3, 4, 5, 6, 7], left: [1, 0] },
    { pos: 7, right: [8, 0], left: [6, 5, 4, 3, 2] }
  ];

The idea is create manually animations, so if e.g. one element is in pos=0 and we click 'right' we create 2 animations to reach the positions 1,2

Is a few complex the function, I put comments

  animateViews(direction: string) {
    //with each element of the array [0,2,7]
    this.animates.forEach((x: number, index: number) => {
      //get the item and the mov
      const mov = this.movements.find(m => m.pos == x);
      const item = this.itemsView.find((_x, i) => i == index);

      //create an array of animations
        const animations = mov[direction].map(m => {
          const angle = (m * 2 * Math.PI) / 9;
          const scale = (75 + 25 * Math.cos(angle)) / 100;
          const applystyle = {
            left: -75 + 150 * Math.sin(angle) + "px",
            transform: "scale(" + scale + ")",
            position: "absolute",
            "z-index": Math.floor(100 * scale)
          };
          return animate(
            this.timer / mov[direction].length + "ms",
            style(applystyle)
          );
        });

        //we create the animation with builder.build
        const myAnimation = this.builder.build(animations);

        //the animation is applied to the element
        this.player = myAnimation.create(item.nativeElement);

        //when finished, change the value of the array [0,2,7]
        this.player.onDone(
          () =>
            (this.animates[index] = mov[direction][mov[direction].length - 1])
        );
        this.player.play();
    });
  }

the new stackblitz

Update 3*: To undestand the formulas, take paper and pencil and a use a few mathematics: Imagine a circunference with a radius "r". Draw a vertical line from the center and mark a point in the circunference. Call "angle" to the angle in clockwise from the vertical to the line that join the point with the cencer of the circunference.

left=r*Math.sin(angle)-width_of_img/2

For the scale we need remember that when "angle" is 0 scale is 1, and when "angle" is 180 degrees scale is 0.5 (or another number between 1 and 0 -more less, more depth). Call "minScale" to this value. This mean that Math.cos(0)=1 scale is 1 and Math.cos(180degrees)=-1 scale is minScale. So

 scale=(1+minScale)/2+(1-minScale)/2*Math.cos(angle)

Upvotes: 4

user11475999
user11475999

Reputation:

this might help you

https://github.com/Wlada/angular-carousel-3d

If you use bower, just run bower install angular-carousel-3d. If not, download files angular-swipe.js, carousel-3d.css, and carouse3d.js from the following github repos :

Angular Swipe
Angular Carousel 3D

Note: you can download and use the minified versions as well.

Add theses files to your code:

<link href="carousel-3d.css" rel="stylesheet" type="text/css" />
<script src="angular.js"></script>
<script src="angular-swipe.js"></script>
<script src="carousel-3d.js"></script>

Add the angular-carousel-3d module as a dependency to your application module:

angular.module('MyApp', ['angular-carousel-3d']);

In your template : Add a carousel-3d attribute to any element. Add ng-model with your array of objects Add carousel3d-slide directive and ng-repeat to render slides

<div carousel3d ng-model="arrayOfObjects">
    <div carousel3d-slide ng-repeat="slide in app.slides track by $index">
        <figure>
            <img ng-src="{{slide.src}}" alt=""/>
            <figcaption ng-bind="slide.caption"></figcaption>
        </figure>
    </div>
</div>

Upvotes: 0

hugh
hugh

Reputation: 92

As you're new to Angular, I suggest you a way to work with 3rd-party components:

  1. Search for the Angular component that suite your need or Angular framework which has tools to help you build your component.
  2. Import it to your project (use npm install ...). Normally almost 3rd-party components will guide you how to install itself.
  3. Import the installed component to your project's .module.ts file then use it.

Upvotes: 0

Related Questions