Angular Animation 應用 - Blink 效果

Posted by Ryan Tseng on 2018-08-08

這篇文章的標題真的很難下,因為主要是搭配以下兩種技術來實作

  • socket.io (其實可以直接用 rxjs 的 interval 來跑,這個不是必要的技術)
  • angular 6

大家一定都常常看到某些看股票的網頁,如果上升和下降都會閃爍一下,表示有變化

但今天這篇文章要再進階一點,如果數字上升,就會閃一下綠色,反之就會閃一下紅色

環境

  • Windows 10 Pro
  • Webstorm 2018.2

最近迷上了 Typescript,所以 socket.io 的部分將會使用 Typescript 來實作,並且使用 Webpack 來進行打包,這篇文章將會附上部分的程式碼,給各位參考

socket.io

大概說明一下 socket.io 的部分主要是在定義 namespace 和使用 rxjs 的 interval 來不斷的產生隨機的數字,並且透過名為 random 的 event,來將數字送到前端去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import * as express from 'express';
import * as socketIo from 'socket.io';
import {createServer, Server} from "http";
import {interval} from 'rxjs';
import {tap} from "rxjs/operators";


export class WebSocketServer {

private app: express.Application;
private server: Server;
private io: socketIo.Server;
private readonly SERVER_IP: string;
private readonly SERVER_PORT: number;

constructor(ip?: string, port?: number) {
this.SERVER_IP = ip || '127.0.0.1';
this.SERVER_PORT = port || 8080;
this.initialize();
this.start();
}

private initialize() {
this.app = express();
this.server = createServer(this.app);
this.io = socketIo(this.server);
}

start() {
this.server.listen(this.SERVER_PORT, this.SERVER_IP, () => {
console.log(`server is running on ip: ${this.SERVER_IP}, port: ${this.SERVER_PORT}`)
});

// namespace
this.io.of('/animation').on('connection', (socket: socketIo.Socket) => {
console.log(`a client with id ${socket.client.id} connect on port ${this.SERVER_PORT}`);
// 每 500 毫秒送出一次隨機的數字
interval(500)
.pipe(
tap(() => {
// 向名為 random 的事件發出隨機數字
socket.emit('random', Math.floor(Math.random() * 100));
})
).subscribe();

});
}

get expressApp(): express.Application {
return this.app;
}

}

這邊是 webpack 的打包定義檔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
mode: 'development',
target: "node",
entry: path.resolve(__dirname, './src/index.ts'),
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader'
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: "bundle.js",
path: path.resolve(__dirname, 'dist')
},
externals: [
nodeExternals()
]
};

angular

來到前端的部分,如果要使用 socket.io 的 client 只要使用 yarn 或著 npm 照以下指令安裝相關 packages 即可

1
2
3
4
5
6
7
# socket.io-client
yarn add socket.io-client
npm install --save socket.io-client

# @types/socket.io-client
yarn add --dev @types/socket.io-client
npm install --save-dev @types/socket.io-client

為了讓我們有點長的 animation 不要讓 component 的程式看起來太亂,所以我把它搬到另外一個 typescript 檔案。

基本上我們會預先定義兩個狀態,一個是 plus 另外一個是 minus 狀態,而 transition 裡面定義的就是從哪個狀態改變到另外一個狀態的時候,要撥放什麼動畫,為了營造那種閃爍的效果,所以我們定義 0.5 秒內要將畫面從透明變成紅色/綠色,再變回透明(看起來就是背景會閃一下)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// /models/animations.ts

import {
animate,
keyframes,
state,
style,
transition,
trigger
} from '@angular/animations';


export const valueChangeAnimation = trigger('state', [
state('plus', style({})),
state('minus', style({})),
transition(
'* => plus',
animate(
'0.5s',
keyframes([
style({ backgroundColor: 'transparent' }),
style({ backgroundColor: 'green' }),
style({ backgroundColor: 'transparent' })
])
)
),
transition(
'* => minus',
animate(
'0.5s',
keyframes([
style({ backgroundColor: 'transparent' }),
style({ backgroundColor: 'red' }),
style({ backgroundColor: 'transparent' })
])
)
)
]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { AfterViewInit, Component } from '@angular/core';
import { valueChangeAnimation } from './models/animations';
import * as io from 'socket.io-client';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
animations: [valueChangeAnimation]
})
export class AppComponent implements AfterViewInit {
payload;
state = '-';
nsp: SocketIOClient.Socket;
constructor() {
this.nsp = io.connect('http://localhost:8080/animation');
}

ngAfterViewInit() {
this.nsp.on('random', data => {
if (+this.payload > +data) {
this.state = 'minus';
} else if (+this.payload < +data) {
this.state = 'plus';
}

this.payload = data;
});
}

handleDone(evt) {
if (this.state !== '-' && this.state === evt.toState) {
this.state = '-';
}
}
}

使用以上程式碼,將 angular 及 socket.io 分別執行,就可以看到自然的閃動了

參考連結