ReFlex Logo
ReFlex (Title)
Documentation
Navigation

Template: Angular

Table of contents

  1. Basic example
  2. Setup and configuration
  3. Receiving interaction data
  4. Visualization, status and history
  5. Shared types and components

Basic example

Screenshot of basic angular example

Like the Plain HTML template, this example demonstrates how to connect to ReFlex and receive interaction data. It provides a starting point for an Angular client: websocket communication is encapsulated in a service, and components consume the data through observables. The templates reduce the initial setup effort by extracting the essential integration code from earlier projects and presenting it with a consistent visual design.

⬆ back to top

Setup and configuration

The example is part of the repository’s npm workspaces. With Node.js and npm installed, run the following commands from the repository root to install dependencies, build the shared type definitions and start the development server:

1
2
3
npm install
npm run build:shared-types
npm run start:example-angular

Open http://localhost:4201/ in a browser. To create a production build, run npm run build:example-angular from the repository root.

Start the ReFlex server and enable websocket broadcasting with an address matching the template. The development server only serves the Angular application; it does not provide interaction data. The configured websocket endpoint must be reachable from the browser.

The address is defined in examples/basic-angular/src/environments/environment.ts:

1
2
3
4
export const environment = {
  production: false,
  websocketUrl: 'ws://localhost:40001/ReFlex'
};

For production builds, set the address in src/environments/environment.prod.ts as well. The production configuration in angular.json replaces the development environment file with this file. Both currently use the same websocket address.

In src/main.ts, the address is registered under the WEBSOCKET_URL injection token and passed to Angular when bootstrapping AppModule:

1
2
3
4
5
6
const providers = [
  { provide: 'WEBSOCKET_URL', useValue: environment.websocketUrl, deps: [] }
];

platformBrowserDynamic(providers).bootstrapModule(AppModule)
  .catch(err => console.error(err));

⬆ back to top

Receiving interaction data

The central class is TouchPointService in src/services/touch-point.service.ts. It is registered with providedIn: 'root', so the components share one service instance and websocket connection. Its constructor receives the configured address, creates a native WebSocket and registers the event handlers:

1
2
3
4
constructor(@Inject('WEBSOCKET_URL') private _address: string) {
    this._wss = new WebSocket(this._address);
    this.subscribeWebSocketEvents();
}

For each onmessage event, the service increments a local frame counter, parses the JSON array of interactions and publishes the resulting data. Before parsing, it converts the first character of JSON property names to lowercase so that server properties such as TouchId and Position match the TypeScript fields touchId and position. The following excerpt shows this conversion:

1
2
3
4
5
6
const lowerCaseStart = evt.data.replace(/"([^"]+)":/g,
  ($0: string, $1: string) => {
    return ('"' + $1.charAt(0).toLowerCase() + $1.slice(1) + '":');
  });

var points = JSON.parse(lowerCaseStart);

The service exposes the following methods:

Method Result Purpose
getTouchPoints() Observable<Interaction[]> Publishes the current interaction points, including an empty array when no interactions are present.
getHistory() Observable<InteractionFrame[]> Publishes the received message history. Each entry contains a local frameId and its interactions.
getFrameNumber() Observable<number> Publishes the number of received websocket messages. This is a client-side counter, not a server frame identifier.
getAddress() string Returns the configured websocket address.
isConnected() boolean Checks whether the websocket’s readyState is OPEN.

Internally, RxJS Subject instances distribute the updates. Connection opening and closing are logged to the browser console. The example keeps connection handling minimal: it has no reconnect control, automatic reconnection or dedicated onerror handler. Reload the page to establish a new connection after the server becomes available again.

⬆ back to top

Visualization, status and history

Interaction points

AppComponent obtains TouchPoints$ from TouchPointService.getTouchPoints(). Its template uses Angular’s async pipe and *ngFor to render one circle per interaction. The essential bindings in src/app/app.component.html are:

1
2
3
4
5
6
<div *ngFor="let tp of TouchPoints$ | async">
  <div class="touchPoint" [style]="'transform: translate('+tp.position.x * this.Width+'px, '+tp.position.y * this.Height+'px) scale('+Math.abs(tp.position.z)+');'">
    <div class="touchPoint__outerCircle {{tp.position.z < 0 ? ' push' : ' pull'}}"></div>
    <div class="touchPoint__innerCircle"><p>{{tp.touchId}}</p></div>
  </div>
</div>

Connection status

StatusComponent in src/app/status/ displays the websocket address, frame counter and touch count. It subscribes to the frame and interaction observables and checks the connection state every 500 ms. A green indicator denotes an open connection; a red indicator denotes a connection that is not open.

Message history

HistoryComponent in src/app/history/ subscribes to getHistory(). It displays each frame’s local identifier and serializes its interactions with JSON.stringify. The message container uses flex-direction: column-reverse, placing newer messages at the bottom.

The service includes a history limit of 100 entries in the branch handling non-empty interaction arrays. Empty arrays are also recorded, but that branch returns before applying the limit. Consequently, a sequence of empty frames can grow the history beyond 100 entries. This is an in-memory display of incoming data; the Angular template does not send messages to the logging backend used in the extended HTML example.

⬆ back to top

Shared types and components

Shared TypeScript definitions

The package @reflex/shared-types in packages/reflex-shared-types/ provides reusable TypeScript definitions corresponding to the framework’s data structures. The Angular template references this local package through its workspace dependency and imports Interaction and InteractionFrame for the service and components.

Interaction contains touchId, position (Point3 with x, y and z), type, extremumDescription, confidence and time. InteractionFrame groups an array of interactions with a frameId. These interfaces make received data available to TypeScript code with consistent field names; they do not validate websocket payloads at runtime.

Angular component library

The separate package @reflex/angular-components in packages/reflex-angular-components/ provides reusable interface elements extracted from the server frontend, together with shared styles and assets. Its public components include PanelHeaderComponent, SettingsGroupComponent, OptionCheckboxComponent, ValueSelectionComponent, ValueSliderComponent and ValueTextComponent.

See the component documentation for the available interface elements and the style guide for the shared visual design.

The basic-angular template implements its own visualization, status and history components and does not import this library. For an interactive demonstration of the shared components, their setup and the style guide, use the separate project in examples/shared-components-demo/. After installing the workspace dependencies, run these commands from the repository root:

1
2
npm run build:shared-components
npm start --workspace examples/shared-components-demo

The component demo is served at http://localhost:4203/.

⬆ back to top