0

I have a component that is usually dormant (by which I simply mean it is of little interest to the user), but in a certain state this component becomes 'activated' and I want to put it in the exact center of the screen and enlarge it to grab the user's attention.

There are several of these components in the dormant state, but only ever 1 activated. The dormant components could be anywhere on the screen, so I wanted a solution that would translate the component from wherever it was originally to the middle of the screen while activated, and then return it back to its original dormant position when done.

Attempting to do this:

template:

<div #myElement [@isActivated]="activated">
    Hello Stack Overflow
    <button (click)="activated = activated === 'activated' ? 'dormant' : 'activated">
        Toggle
    </button>
</div>

typescript:

@Component({
  // ...
  animations: [
    trigger('isActivated', [
      state('dormant', style($transitionToActivated)),
      state('activated', style({
        transform: 'translateX(0%) translateY(0%) scale(1)'
      })),
      transition('dormant => activated', animate('1000ms ease')),
      transition('activated => dormant', animate('1000ms ease'))
    ])
  ]
})
export class MyComponent implements OnInit {
    @ViewChild('myElement') myElement: ElementRef;
    activated = 'dormant';
    transitionToActivated: any;

    ngOnInit() {
        let rect = this.myElement.nativeElement.getBoundingClinetRect();
        this.transitionToActivated = {
            transform: ''translateX(' + ((window.screen.width / 2) - (rect.right + rect.left) / 2) + ') translateY(' +
                ((window.screen.height / 2) - (rect.top + rect.bottom) / 2) + ') scale(1.5)'
        }
    }
}

My syntax here is off: the $transitionToActivated inside of the Component decorator is invalid. Is it possible to this kind of responsive animations with Angular Animations? Or will I need to look into a pure CSS solution?

[here's a plunker of what I'm trying... currently my attempt to put it in the exact center is commented out, and just some static animation instructions]

ZackDeRose
  • 2,146
  • 1
  • 16
  • 28
  • can you try these variables as input parameter..? like mentioned in the link below ? https://www.yearofmoo.com/2017/06/new-wave-of-animation-features.html#how-to-use-animation-input-parameters – Aravind S Jan 25 '18 at 07:59
  • hey @AravindS, do you know the syntax (or if you even can) put variables into the {time: "1s", opacity: "1"} object from the link you sent? Double mustache? – ZackDeRose Jan 26 '18 at 03:45

1 Answers1

0

I figured out a couple things.

First, above I'm using window.screen for width and height of the 'screen.' This is actually giving me the resolution of the monitor (resizing the window doesn't affect it). I wanted document.documentElement to get the size of the viewport.

Second, I solved the issue of dynamic animations by using the AnimationPlayer to define the animations programmatically [rather than defining them in the Component decorator as I was trying to above].

I'm still curious as to whether the animations can be dynamically changed via the animation property inside the component decorator... I expect there must be a way, but I've been rather frustrated by the hand-wavy-ness of the Angular animations API and still can't figure it out.

Also, my solution acts funky when the viewport size is changed while in the 'activated state' (doesn't respond to resizing [as would be expected] and jumps at the start of its 'return' animation to the new middle of the viewport [again as expected].

Here's code and plunker to my solution:

export class App implements OnInit {
  @ViewChild('myElement') myElement: ElementRef;
  activated: BehaviorSubject<string> = new BehaviorSubject<string>('dormant');
  transitionToActivated: any;
  player: AnimationPlayer;
  factory: any;

  constructor(private builder: AnimationBuilder) {}

  ngOnInit() {
    console.log('viewport width: ' + document.documentElement.clientWidth);
    console.log('viewport height: ' + document.documentElement.clientHeight);
    let rect = this.myElement.nativeElement.getBoundingClientRect();
    console.log('rect right: ' + rect.right);
    console.log('rect left: ' + rect.left);
    this.transitionToActivated = 'translateX(' + ((document.documentElement.clientWidth / 2) - 
        (rect.right + rect.left) / 2) + 'px) translateY(' + 
        ((document.documentElement.clientHeight / 2) - (rect.top + rect.bottom) / 2) + 
        'px) scale(1)';

    this.activated.subscribe(newValue => {
      this.transitionToActivated = 'translateX(' + ((document.documentElement.clientWidth / 2) - 
        (rect.right + rect.left) / 2) + 'px) translateY(' + 
        ((document.documentElement.clientHeight / 2) - (rect.top + rect.bottom) / 2) + 
        'px) scale(1)';
      console.log(this.transitionToActivated);
      if(newValue === 'activated'){
        this.factory = this.builder.build([
          style({ transform: 'translateX(0) translateY(0) scale(1)' }),
          animate(
            '1000ms', 
            style({ transform: this.transitionToActivated })
          )
        ]);
        this.player = this.factory.create(this.myElement.nativeElement, {});
        this.player.play()
      } else if(newValue === 'dormant'){
        this.factory = this.builder.build([
          style({ transform: this.transitionToActivated })
          animate(
            '1000ms', 
            style({ transform: 'translateX(0) translateY(0) scale(1)' }),
          )
        ]);
        this.player = this.factory.create(this.myElement.nativeElement, {});
        this.player.play()
      }
    })
  }
}
ZackDeRose
  • 2,146
  • 1
  • 16
  • 28