In this article, I’d like to submit the tiny guide for Perspective usage in the Angular application. Perspective is the powerful data visualization component. It is based on JS + WebAssebmly or Python, supports Apache Arrow, CSV, JSON formats. More information about Perspective is available by this link.

First of all, we need an Angular application. If you don’t have one, you can create it by calling the command below.

ng new name-of-app

The second step is adding the Perspective dependencies in package.json:

 
{
    "dependencies": {
        "@finos/perspective": "^0.6.2",
        "@finos/perspective-viewer": "^0.6.2",
        "@finos/perspective-viewer-d3fc": "^0.6.2",
        "@finos/perspective-viewer-datagrid": "^0.6.2",
        "@finos/perspective-viewer-hypergrid": "^0.5.2",
        "@finos/perspective-webpack-plugin": "^0.6.2", 
    },
    "devDependencies": {
        "@webcomponents/webcomponentsjs": "^2.5.0", 
    }
}

The next step is providing the webpack configuration for the perspective-webpack-plugin. Create webpack.config.js and place this config in it.

import PerspectivePlugin from "@finos/perspective-webpack-plugin";

export const entry = "./in.js";
export const output = {
    filename: "out.js",
    path: "build"
};
export const plugins = [new PerspectivePlugin()];

Then, in the angular.json we need to add the webcomponent.js asset’s configuration.

{
  "projects": {
    "perspective-angular": {
      "architect": {
        "build": {
          "options": {
            "assets": [
              "src/favicon.ico",
              "src/assets",
              {
                "glob": "**/*.js",
                "input": "node_modules/@webcomponents/webcomponentsjs",
                "output": "node_modules/@webcomponents/webcomponentsjs"
              }
            ]
          }
        }
      }
    }
  }
}

We need to edit the polyfills.ts file. Add ‘ (window as any).global = window; ‘ for the node compatibility.

The main.ts should look like this:

import {enableProdMode} from '@angular/core';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';

import {AppModule} from './app/app.module';
import {environment} from './environments/environment';

declare global {
  interface Window {
    WebComponents: {
      ready: boolean;
    }
  }
}

if (environment.production) {
  enableProdMode();
}

function bootstrapModule() {
  platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.log(err));
}

if (window.WebComponents.ready) {
  bootstrapModule();
} else {
   window.addEventListener('WebComponentsReady', bootstrapModule);
}

In the index.html, in the head tag, add the following code.

  <script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
  <script>
    if (!window.customElements) {
      document.write('<!--');
    }
  </script>
  <script src="node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
  <!-- ! DO NOT REMOVE THIS COMMENT, WE NEED ITS CLOSING MARKER -->
  <script src="https://unpkg.com/@finos/perspective-viewer-d3fc"></script>

Manual import perspective-viewer-d3fc from the CDN is a temporary solution for chart visualization fixing.

Then, we need to provide the custom element schema in the application module file.

import { NgModule,CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})

After all these preparations, we can configure our components.

In the less (css/sass/scss) component’s file, add import Perspective’s themes, and feel free to provide your own styles.

@import "../../node_modules/@finos/perspective-viewer/src/themes/all-themes.less";

perspective-viewer {
  position: relative;
  width: 100%;
  height: 600px;
}

Add the perspective-viewer in the component’s html.

<perspective-viewer class='perspective-viewer-material-dense'></perspective-viewer>

The last step is component.ts configuration. Provide necessary imports, define the worker, provide data to the viewer.

import {Component, OnInit} from '@angular/core';
import {HTMLPerspectiveViewerElement} from '@finos/perspective-viewer';
import perspective, {PerspectiveWorker} from '@finos/perspective';
import '@finos/perspective-viewer';
import '@finos/perspective-viewer-hypergrid';
import '@finos/perspective-viewer-datagrid';
import '@finos/perspective';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.less'],
})
export class AppComponent implements OnInit {
  private worker: PerspectiveWorker;

  constructor() {
    this.worker = perspective.worker();
  }

  ngOnInit() {
    const viewer: HTMLPerspectiveViewerElement = document.getElementsByTagName('perspective-viewer')[0] as HTMLPerspectiveViewerElement;
    const table = this.worker.table(this.getData());
    viewer.load(table);
    viewer.toggleConfig();
    viewer.editable = true;
    viewer.plugin = 'hypergrid';
  }

  private getData() : Object[] {
    return [
      {
        "LatD": 41,
        "LatM": 5,
        "LatS": 59,
        "NS": "N",
        "LonD": 80,
        "LonM": 39,
        "LonS": 0,
        "EW": "W",
        "City": "Youngstown",
        "State": " OH"
      },
      {
        "LatD": 42,
        "LatM": 52,
        "LatS": 48,
        "NS": "N",
        "LonD": 97,
        "LonM": 23,
        "LonS": 23,
        "EW": "W",
        "City": "Yankton",
        "State": " SD"
      }
    ]
  }
}

}

That’s all! The source code of this example is available on Github.