0

Consider the following code:

<div class="red-square" 
     *ngIf="someCondition"
     [@showHideAnimation]
></div>

Is there a way to cause aforementioned div to disappear with random animation?

Random animation being, for example, rotation of the object by any number of degrees between, say, 30 and 150.

Alex Lomia
  • 6,705
  • 12
  • 53
  • 87

3 Answers3

2

I have an idea, but it's not randomized per se.

given your animation

animations: [
  trigger('animationName', [
    state('void', style({
      // hidden case
    })),
    state('*', style({
      // visible case
    })),
    transition(':enter', animate('TIME [DELAY] EASING')),
    transition(':leave', animate('TIME [DELAY] EASING'))
  ])
]

What you could do is make a global function like so

function randomizeAnimation(propertiesNumber: number, state: number) {
  let properties = ['borderBottom', 'opacity', 'All of the properties you want to animate here'];
  let randomIndex = () => Math.random() * properties.length;

  let style = {};
  for (let i = 0; i < propertiesNumber; i++) {
    let index = randomIndex();
    let voidValue = '0';
    let showValue = '*';
    // Why it's not "randomized" : you need to make custom rules here. Example : colors
    if (properties[index].toLowerCase().includes('color')) { 
      let RdmOct = () => Math.random() * 256;
      let generateRandomColor = () => `rgb(${RdmOct()}, ${RdmOct()}, ${RdmOct()})`;
      voidValue = generateRandomColor();
      showValue = generateRandomColor();
    }
    style[properties[index]] = state ? voidValue : showValue;
  }
  return style;
}

What this function does is that it takes a number of properties to animate, and an animation state (boolean, or 0/1). It then choses random properties in its array, making it "random". If the properties have a special use case, such as colors (the wildcard '*' won't work), then you have to handle it. Once it has created the random style, it returns it to be used in the animate function. It's not "randomized" like a Math.random(), but it could do the trick !

In your component, you can now call this function in your animate :

animations: [
  trigger('animationName', [
    state('void', style(randomizeAnimation(1, 0))),
    state('void', style(randomizeAnimation(1, 1))),
    transition(':enter', animate('275ms ease-out')),
    transition(':leave', animate('275ms ease-in'))
  ])
]

I'm not sure it would work, but that's close enought for your need I guess !

EDIT you could even go further by setting an Interval in your animate, changing the animation every minute or so. But if this method doesn't even work ... I won't lose more time to write this one ahah

  • Nice idea. I tested it and **once certain animation is generated for an element, it has that same animation until the application is refreshed**. Not quite what I was looking for, but pretty close nonetheless. – Alex Lomia Nov 10 '17 at 07:11
  • Glad to know it works ! Did you try with a timeout ? –  Nov 10 '17 at 07:30
  • Tried to change the animations every 500ms with `setInterval`, but it didn't work – Alex Lomia Nov 10 '17 at 08:01
  • Where did you put the Interval ? into the function, or at the function call ? Also, maybe you should destroy the component first, this means going to another page and coming back. But again, that's just me assuming, I've never even tried this. –  Nov 10 '17 at 08:02
  • I created a variable and kept assigning it new styles every 500ms while feeding it to the animations section in the component's metadata. I hope it makes sense. Your other idea, destroying and re-creating a component might actually work, haven't tested yet. – Alex Lomia Nov 10 '17 at 08:50
1

For animations with random values you will need to create animations that accept parameters. This will allow you to provide different values in the animation so that you can get random behavior. You will need to setup one or more animations depending on what you want to animate and set parameters on the values like so:

animations: [
    trigger('randomAnimation', [
        transition('* => colorFade', [
            animate("500ms ease-in", keyframes([
                style({'background-color': "{{color}}"}),
                style({'opacity': "{{opacity}}"}),
            ]))
        ], {params : { color: "yellow", opacity: "0" }}),
        transition('rotateFade', [
            animate("{{time}}ms ease-in", keyframes([
                style({'transform': 'rotate({{rotate}}deg);'}),
                style({'opacity': "{{opacity}}"}),
            ]))
        ], {params : { time: "500", rotate: "45", opacity: "0.6 }})
    ])
]

And then in the view you can bind the animation to an animation object that has the random values in it.

<div class="red-square" [@randomAnimation]="animationConfig"></div>

And in your component you can create the object that will make the animation random.

public setRandomAnimation() {
    this.animationConfig = {
        value: Math.random() > 0.5 ? 'colorFade' : 'rotateFade',
        params: {
            time: Math.floor(Math.random() * 5000) + 200,
            color: `#${(Math.floor(Math.random() * 255)).toString(16)}${(Math.floor(Math.random() * 255)).toString(16)}${(Math.floor(Math.random() * 255)).toString(16)}`,
            opacity: Math.random(),
            rotate: Math.floor(Math.random() * 360),
    };
}

The above method is just an example you could expand this much further and not cram it all into one method. The parameters that are not used by the animation will be ignored so it is okay to specify rotate even though it is not used in colorFade for example.

PREVIOUS ANSWER

You can define any number of animation states and then set up transitions so that when they go from any state to a specific state a certain animation will occur. Here is an example of what the animation states might look like:

animations: [
  trigger('randomAnimation', [
    transition('* => yellowDisappear', [
      animate(300, keyframes([
        style({'background-color': 'yellow'}),
        style({opacity: 0})
      ])),
    transition('* => rotateFade', [
      animate(300, keyframes([
        style({'transform': 'rotate(45deg);'}),
        style({opacity: 0.6})
      ]))
  ])
]

You can then specify the animation that you want to apply in the template.

<div class="red-square" [@randomAnimation]="'yellowDisappear'"></div>
<div class="red-square" [@randomAnimation]="'rotateFade'"></div>

If you want to have it occur randomly I would set up some kind of Observable that would change the animation randomly and if you want it to occur on certain conditions then I would make a method in the component to set the current state of the animation based on certain conditions.

Animations in Angular are a little tricky but there is good information in the tutorial and Matias Niemelä (one of the lead developers of the Angular animation module) wrote a good article on it as well. I would recommend checking these out if your project is going to make use of animations

Community
  • 1
  • 1
Teddy Sterne
  • 13,774
  • 2
  • 46
  • 51
  • Problem with this approach is that the number of animation states is **finite**. What I am trying to achieve is, for example, "rotation of the square randomly anywhere from 30 to 150 degrees". – Alex Lomia Nov 10 '17 at 07:16
0

I'm not sure if this will work, but you can add a state to the animated div like so:

<div class="red-square" 
     *ngIf="someCondition"
     [@showHideAnimation]="getRandomState()"
></div>

The getRandomState method can return a couple of predefined strings randomly.

Next you only need to create transitions for each of these strings to void, for example:

transition('yellowFirstState => void',[
  style({'background-color':'yellow'}),
  animate(100)
])
Venomy
  • 2,076
  • 15
  • 25
  • There are only so many states you can manually define, they are **finite**. – Alex Lomia Nov 10 '17 at 07:18
  • Yes, that's true. Sadly I don't know a way to make it infinite and dynamic. trichetriche's solution is probably the closest you're going to get :) – Venomy Nov 10 '17 at 07:29