Skip to content
This repository has been archived by the owner on Nov 15, 2022. It is now read-only.

Extensions

Christian Zirkelbach edited this page Apr 29, 2020 · 31 revisions

Extension Overview

The extensions are currently being refactored or (re-)engineered in order to be compatible with a noted stable version of ExplorViz.

Status Description
✔️ working
🚧 is (re-)engineered at the moment
needs to be (re-)engineered

Available

Extension Name Version Description Backend Extension Status Frontend Extension Status Working with ExplorViz Version
Virtual Reality Mode 2.0 A VR visualization multi-user mode for a more immersive, collaborative comprehension process. Compatible with the Color Picker extension to enable also visually impairment color palettes ✔️ ✔️ 1.5.0
Color Picker 1.5.0 Ability to use a visually impaired colorization and definable color palettes for visualization no extension ✔️ 1.5.0
Tutorial Mode master branch Allows to design, build, and execute user-oriented tutorials ✔️ ✔️ 1.4.0
Dashboard master branch Adds a (performance) dashboard for monitored software landscapes and applications ✔️ ✔️ 1.4.0

Planned

Extension Name Description Backend Extension Status Frontend Extension Status
Version Comparison Offers a visual comparison between two selected versions of a software landscapes and applications
Architecture Conformance Checking Allows a visual comparison between a modelled software landscape and a monitored one
Model Editor Provides a WYSIWYG editor for creating software landscapes and included applications

Extension Installation

At the moment installing extensions (called addons in the frontend) is only possible in the development setup.

Frontend

Install (remote) an Addon

Run npm install <git-URL>or ember install <git-URL>. Changes in your addon require ember init. If you want to install a specific version of an extension, add a git tag at the end of the url, e.g. npm install https://github.com/ExplorViz/explorviz-frontend-extension-vr.git#1.5.0.

Remove an Addon

Remove the addon from application's package.json. Then run npm prune.

Extension Development

Backend

Since ExplorViz's backend is defined as a RESTful Web service utilizing the Jersey framework, data exchange is based on resources (e.g. LandscapeResource). Extensions may consist of multiple computations, classes etc., but in the end they transport and receive data via one or more resources.

Development

Follow the instructions in the provided Dummy Extension.

Accessing the data model

In order to access the data model in an extension, please use the provided API and its included Interface, which is documented here.

Frontend

In order to create an extension (or addon in ember space) run ember addon <addon-name>. The main direcotry of your addon is the subdirectory addon/. Everything that you generate (routes, templates, components,..) will be put in the addon/ folder and finally exported in app/ automatically, thus it will be merged with the application's namespace. Normally, you do not have to change anything in app/. For more information about developing an Ember addons visit EmberCLI-Extending.

Development Hints

Setup

After generating your Ember addon make sure that ember-cli-htmlbars in the file package.json is an entry of dependencies and not devDependencies.

Connecting to core

The next step will make your addon's routes (and code) accessible to the explorviz-frontend. Create an instance-initializer with ember g instance-initializer <addon-name>. This instance-initializer will add the addon routes to the applications router and insert labels for the buttons in the navigation menu. Your addon is then reachable via a single navbar entry. It should look like this:

//your-addon-name/addon/instance-initializers/myinitializer.js
import Router from "explorviz-frontend/router";

export function initialize(appInstance) {

  const service = appInstance.lookup("service:page-setup");

  if(service){
    service.get("navbarRoutes").push("Discovery");
  }

  Router.map(function() {
    this.route("Discovery");
  });
}

export default {
  name: 'explorviz-frontend-extension-discovery',
  initialize
};

Reset Route

Most of the time the entry point of your extension is a Ember Route. Your routes are automatically added to the frontend's navbar and therefore are easily invocable by clicking the respective navbar entry. Every route should always extend the frontend's base-route as shown below:

//your-addon-name/addon/routes/myroute.js
import BaseRoute from 'explorviz-frontend/routes/base-route';

export default BaseRoute.extend({

  actions: {
    // @Override BaseRoute
    resetRoute() {
      // your cleanup code here
    }
  }

});

The resetRoute is called whenever users click on the navbar entry of the route. It does not cleanup anything on its own, you have to define the cleanup code first. Have a look at resetView in the visualization route, the corresponding controller and the visualization route template for starters.

Authentication

Pass AuthenticatedRouteMixin to every route you add. This way users have to login in order to access your route. Base on the example above, it should look like this:

//your-addon-name/addon/routes/myroute.js
import BaseRoute from 'explorviz-frontend/routes/base-route';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';

export default BaseRoute.extend(AuthenticatedRouteMixin, {

  actions: {
    // @Override BaseRoute
    resetRoute() {
      // your cleanup code here
    }
  }

});

How to use CSS

Create a file called style.css in your addon's vendor folder. Then, open the addon's index.js file and apply necessary changes based on the following code segment

//your-addon-name/index.js
module.exports = {
  name: 'your-addon-name',

  included: function(app) {
    this._super.included.apply(this, arguments);    
    app.import('vendor/style.css');
  }
};

Render a landscape or application

You can use the ready-made landscape and application visualizations in your extension. This is useful, if you for example create custom landscapes or applications and simply want to use the existing rendering. Add the following in your extension's route template, where yourCustomLandscape is your landscape (see Visualization route template and the corresponding route's controller). Note the variable binding:

//your-addon-name/addon/templates/myroute.hbs
{{visualization/rendering/landscape-rendering latestLandscape=yourCustomLandscape}}

If you continuously change entities of your overall landscape, you have to call the globally accessible redrawScene function of the renderingService, e.g. in your route's controller:

//your-addon-name/addon/controller/myroute.js
import { inject as service } from "@ember/service";

export default MyRoute.extend({
  renderingService: service(),

  updateModel() {
    // update your entity and then call
    this.get('renderingService').redrawScene();
  }
});

If you need to listen to events (singleClick, doubleClick) and execute your custom code, do the following (similar for application interaction). Again, note the binding in the template:

//your-addon-name/addon/controller/myroute.js
import { inject as service } from "@ember/service";
import { getOwner } from '@ember/application';
import LandscapeInteraction from
    'explorviz-frontend/utils/landscape-rendering/interaction';

export default MyRoute.extend({
  renderingService: service(),

  updateModel() {
    // update your entity and then call
    this.get('renderingService').redrawScene();
  },

  initMyListeners() {
    const landscapeInteraction = LandscapeInteraction.create(getOwner(this).ownerInjection());
    this.set('landscapeInteraction', landscapeInteraction);

    this.get('landscapeInteraction').on('singleClick', function(emberModel) {
      console.log(emberModel);
    });

    this.get('landscapeInteraction').on('doubleClick', function(emberModel) {
      console.log(emberModel);
    });
  }
});
//your-addon-name/addon/templates/myroute.hbs
{{visualization/rendering/landscape-rendering latestLandscape=yourCustomLandscape interaction=landscapeInteraction}}

You can even customize your interaction object and for example define a complete new behavior for the single click handler:

//your-addon-name/addon/controller/myroute.js
import { inject as service } from "@ember/service";
import { getOwner } from '@ember/application';
import LandscapeInteraction from
    'explorviz-frontend/utils/landscape-rendering/interaction';

export default MyRoute.extend({
  renderingService: service(),

  updateModel() {
    // update your entity and then call
    this.get('renderingService').redrawScene();
  },

  initMyListeners() {
    const landscapeInteraction = LandscapeInteraction.create(getOwner(this).ownerInjection());
    landscapeInteraction.handleSingleClick = function(mouse) {
      // console.log(mouse);
      // do your stuff, but keep in mind that the pre-defined functionality
      // is now gone
    };

    this.set('landscapeInteraction', landscapeInteraction);    
  }
});

Working locally

If you want to test your addon against the application without installing it all the time, use npm link to link your addon to the application locally. Enter the following commands in your CLI (you might need to use sudo):

  1. npm link in the addons root folder
  2. npm link <your-addon-name> in the frontends root folder
  3. Add "<your-addon-name>": "latest" at the end of the devDependencies in the frontends package.json
  4. ember s in the frontend root folder

Attention: There might be an error, if the frontend dependencies are updated, while you are working locally with your addon. Be sure to temporally remove "<your-addon-name>": "latest" from the frontends package.json. Then update your dependencies and readd "<your-addon-name>": "latest".

Live reload

You can skip the manual restarting of the embedded web server and use an automatic live reload instead. If you work with npm link we highly recommend this setting. Add the isDevelopingAddon hook to your addons index.js as follows

/* jshint node: true */
'use strict';

module.exports = {
  name: 'explorviz-frontend-extension-X',

  isDevelopingAddon() {
    return true;
  }
};