Skip to content

Commit

Permalink
Merge pull request #16 from Webiks/no-angularjs
Browse files Browse the repository at this point in the history
Migrating away from AngularJS
  • Loading branch information
ramtob authored Sep 14, 2017
2 parents 1c9b390 + 3381b76 commit 73e7de0
Show file tree
Hide file tree
Showing 53 changed files with 11,754 additions and 4,253 deletions.
3 changes: 0 additions & 3 deletions .babelrc

This file was deleted.

3 changes: 0 additions & 3 deletions .bowerrc

This file was deleted.

14 changes: 3 additions & 11 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
logs/*
!.gitkeep
.idea/
dist/
node_modules/
bower_components/
tmp
.DS_Store
.idea
desktop.ini
.travis.yml
npm-debug.log
src/app/TILDOCS-#40699695-v1-ùàâ æëåëàì.docx
*.docx
coverage/
13 changes: 0 additions & 13 deletions .jshintrc

This file was deleted.

23 changes: 23 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
language: node_js
node_js:
- 8
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
script: webpack && npm run test-ci

deploy:
- provider: releases
api_key:
secure: QXZMJz8xt2JK1SuZ5AkVHx6Orb2Ebkb5Lc5YxkrxgWu+xbt6lGAy8mMvj2ytkAu2OuecGtAsnh8tiYVJ6LW7d2fGBDgAjSAL1ZSPi+4GQrddwlTkZ8AfGvCLu9no/+E9G2rpDHixmt+lPUbtCfLbdkQ2WCX4gPKcsUdCHcgZvGb9vGADsMNoDwXM0fGiiBr5FlfcwxH3cL60LX3weJRQMseOXAAxMH9syiu9XHjJNt/Ty/p+xZOCK0NxOzQLp2KYONpuLI86+Hdb+bmgIWlwRHvDa1CgdzXbLl9zqea1fHUxsT9g5GM5jX344Q/SOKsoSdtvb2ddbtsm5IJ23EiiL0muhRjudpyRE48gtkPZUhItB539hrdOHWXtWmNxHu715xU16j4YiyO5J/N6ZThJT8WMcTnEHIJVXSVQTPYTyj6Bl3dQFWUBzyKRO9l2LeueEI2kAEAFa5cd31om/XaQmVNK/CFLz7FR6x7o4/Bvd2aCeI2gQ7eRlJXixYC6px6MdgB7yd5BPQcfDeOeefm5bEqrKWr17OIq//UQEkBmO3OJAKdUN9SNOIjV2DUBwbr7kL1vTosdGzJ0xDSUDmmxrX9SZw7HRY33Whle/GLfloGwo1TVdTgbic1TRO9dxtPhdxd6mY+FAaPFUQBYDNzwnXhxJFEeMKZUDIVqI+MtICA=
skip_cleanup: true
file: dist
on:
tags: true
- provider: npm
email: amitmoryossef@gmail.com
api_key:
secure: WZml/wR8HFO8PSweGV9/W5GzzK2Jix8AUAi+B2HNUDtEn4YjuHjSY4DQkrkIaRSUNktAIA59TQIhJCUoYu+movuGOr/E9VFBqftYaZb+78y98mK0Z1As07feZUs36o3gFNs0qKhNyrMAXaDgqH75Cp6qL6F9B46iTdXkvVb351BWkzX7/B8w7BnfBLWYj8Q+Tt74wR+b/TuVBjYK7LJLtxWGvIOc23984z8S+yxIRmsZVabyZE+8MHavGyQ1Jg/5/dLKQohjzylVK3mlz1j/WlHSl5M46P6gjhbeGLrmImcANWXJI7G31v4h2wP0AnIWYuBIwuAv4RE/ovWy1jl+MY7Go1jubHBusPMnn6w7UTvDxgRdVfp8JCm9H7iHkfKgBLQGDB2DF9aquqC3H7jrH0KX4sbIJs5f0z24iEkQtXMVpHVtSJqbbMeP1OQSlUW6bJifmYmNS6+e61atulf8Ag9XuBK2GjbLD/Tug40LUnjq9zPa7Z1bJxFOCfFif0VLmNJ12aFQZLuCBaxRC+rupWPDM/WzK+7h+HamQFHgX3UG6uW1s6ARv8ymNNRUD5UJTB3TfMK+E/ygoiTHLzfwULgV8XyPpSnEUdyQDDit2tl6IqTpZFTU2ZsaqNH2ew0lKHUFcXHNlhaAIvlXMbtQyV50WO20QDnUsQzl2D5yhz4=
skip_cleanup: true
on:
tags: true
34 changes: 34 additions & 0 deletions BLOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Revisiting Force-Horse: Making a Legacy Plugin Agnostic and Usable
For a while, we at Webiks used our own AngularJS D3.js library for graphs visualizations of real-life data sets, called "[Force-Horse](https://github.com/Webiks/force-horse)".

Force-Horse is an open source Javascript component wrapping a Force Layout and adding some functionalities we found very useful, like Adaptive tuning of forces and constraints parameters, Adaptive rendering cycle, Play/Pause the simulation, Multiple edges between two nodes, Weight the nodes and the edges, etc...

![Force Horse](http://webiks.com/wp-content/uploads/2016/07/force_horse-768x441.png)

While you can read all of the details on the library in Ram's [blog post](http://webiks.com/force-horse-force-layout-component/), the gist of it is having a library that adapts to many types of data, is easily modifiable for developers, supports large data sets, and easily allowing customization of the base SVG's design.

## So... What's New?
Having the library written using AngularJS, forces the user to use a legacy framework. Either the user thinks they can just include AngularJS in the bundle, increasing the bundle, or trying to implement the component for their used framework.
Therefore, we decided to remove the dependency for AngularJS, making the library framework agnostic.

##### Agnostification
We migrated AngularJS out of the library, moving to a standard browser feature - [Custom Elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements), being adopted by most modern browsers. (In case it isn't supported att the moment, there is a tiny [browser polyfill](https://github.com/webcomponents/webcomponentsjs) - see [browsers support](https://caniuse.com/#search=custom%20elements%20v1))
What we love about using Custom Elements, is that all of the main frameworks - Angular, React, Vue, Polymer etc.. - support it for bindings of inputs and outputs, but you don't have to use a framework to use it.

##### Integration
We also made the component much easier to integrate, now creating 2 bundles - one for Javascript and one for CSS - and loading the images as a base64 mask directly inside the CSS, so there is no need when creating a distribution build to copy our assets anymore, just importing our CSS.

##### Tests
The original AngularJS component did not have many tests, so we could not ensure it was working for every user. Now, we added many unit tests for many use cases, to cover all of the grounds we need to be confidant in the stability of this awesome component.
For continues integration we now use Travis-CI, to automatically test and deploy the package.

##### Standards
It's 2017, so we ditched the old ES5 syntax, migrating the entire Javascript code base to ES6, taking advantage of the great things it offers.
Also, we moved from CSS to SCSS, for better style management and versatility.

##### Usage
Using Force-Horse is now as simple as using any other element. The new usage guide can be found in the [README](https://github.com/Webiks/force-horse).

### Wanna Help?
- Working on something similar? [Contribute to our GitHub project](https://github.com/webiks/force-horse)
- Thinking there is something we can improve on? [Let us know](https://github.com/webiks/force-horse/issues)
168 changes: 104 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,105 +1,145 @@
# force-horse

An angular.js wrapper for a d3.js force fayout

#### USAGE

force-horse is implemented as an angular.js 1.4 directive. It can be used either as an HTML element or as an HTML element attribute.

`<force-horse options=”ctrl.options”&gt;&lt;/force-horse>`

or:

`<div force-horse options=”ctrl.options”></div>`

A force-horse element does not have an intrincsic size. It adapts itself to the size that is set by its parent. force-horse is implementing CSS **flex-box** display logic.
## Usage
### Installing
`npm install --save force-horse`
### Loading:
With a modules bundler (recommended):
```js
import 'force-horse'; // Imports the web component, not compiled
// OR
import 'force-horse/dist/main.bundle.js'; // Compiled. Less recommended because can't dedupe
```
```scss
@import 'force-horse/src/index.scss'; // Imports the SCSS index file, not compiled
// OR
@import 'force-horse/dist/style.bundle.css'; // Imports the bundle as CSS, compiled
```
Directly from HTML:
```html
<link rel="stylesheet" type="text/css" href="node_modules/force-horse/dist/style.bundle.css" />
<script type="application/javascript" src="node_modules/force-horse/dist/main.bundle.js"></script>
```
### Using:
From the template
```html
<!-- Web component -->
<force-horse data='{"nodes": [], "links": []}' config='{"anything": true}'></force-horse>
<!-- Angular: Note that you have to add CUSTOM_ELEMENTS_SCHEMA -->
<force-horse [attr.data]="data | json" [attr.config]="config | json"></force-horse>
```
From Javascript:
```js
const forceHorse = document.createElement("force-horse");
forceHorse.setConfig(someConfig);
forceHorse.setData(someData);
someContainer.appendChild(forceHorse);
```

# Options parameters
To be rendered, force-horse must first get `data`, which can be passed as an attribute, or directly using `setData`

Parameters are passed through the options attribute. Currently, this object contains only the data property, which holds the graph's data in the following format:
A force-horse element does not have an intrinsic size. It adapts itself to the size that is set by its parent.
force-horse is implementing CSS **flex-box** display logic.

**data**: the graph data (nodes and links):
```
# Attributes
## Data
The graph's data (nodes and links):
```json
{
nodes: [],
edges: []
"nodes": [],
"links": []
}
```

# API
After initializing the directive, force-horse inserts an object into the `options` object sent to it. This **`forceHorseInstance`** holds inside the force horse API methods. There is one **`forceHorseInstance`** per directive initialized:

**addEventListener** - accepts an event name (String) and a callback (function). For a list of events see **Events** section below.
## Config
Configure options in the component. Defaults to:
```json
{
"showButtons": true,
"showLabels": true,
"numOfLabelsToShow": 10,
"showNodeWeight": true,
"showEdgeWeight": true,
"hideOrphanNodes": false,
"showFilterButton": true,
"showLabelsButton": true,
"showNodeWeightButton": true,
"showEdgeWeightButton": true,
"showOrphanNodesButton": true,
"forceParameters": {
"friction": 0.5,
"charge": -100,
"linkStrength": 1,
"gravity": 0.3,
"linkDistance": 10
}
}
```

# API
You can use the API by querying the `force-horse` element, and accessing `viewer`.
```js
// In JS
const viewer = document.qeurySelector("force-horse").viewer;

// In Angular
// Template: `<force-horse #fh></force-horse>`
@ViewChild('fh') forceHorse: ElementRef;
ngAfterViewInit() {
const viewer = this.forceHorse.viewer;
}
```

# Events
# Outputs

These are the current events. PR's and suggestiong for more are welcome:
**hover**: a node/link is hovered upon
Outputs are event emitters. You can subscribe and unsubscribe in the following way:
```
const subscription = viewer.hoverEvent.subscribe(() => { /* some callback */);
subscription.unsubscribe();
```

**select**: a node/link is selected
These are the current events. PR's and suggestions for more are welcome:
**ready** (`readyEvent`): an SVG is drawn and ready

**dblclick**: a node/link is double-clicked upon
**hover** (`hoverEvent`): a node/link is hovered upon

**filter**: remove the selected nodes/links from the graph
**select** (`selectEvent`): a node/link is selected

# External Config file
force-horse supports an external json file, **forceHorse.json**. In this file one can set whether each of the buttons (see below) is displayed or not.
Also, force layout parameters can be set, and thus to override the parameters that force-horse computes automatically, for a specific implementation.
**dblclick** (`doubleClickEvent`): a node/link is double-clicked upon

The config parameters are:
```
{
"showLabels": false, //show labels on start
"showNodeWeight": false, // show each node weight or uniform size
"showEdgeWeight": false, // show each edge weight or uniform size
"showFilterButton": true, // show the filter toggle button
"showLabelsButton": true, // show the labels toggle button
"showNodeWeightButton": true, // show the nodes weights toggle button
"showEdgeWeightButton": true, // show the edges weights toggle button
"useEdgesWeights": false, //weather to use edges weights or simple edge sum for node weights
"forceParameters": {
"charge": -350,
"linkStrength": 1,
"gravity": 0.2,
"linkDistance": 10,
"friction": 0.5
}
}
```
**filter** (`filterEvent`): remove the selected nodes/links from the graph

The forceHorse project contains a complete **demo application**. The demo application is also available on the [plunker](http://embed.plnkr.co/SYmehtaAnQVyMpLJJY2B/?show=preview) site.
The forceHorse project contains a complete **demo application**. The demo application is also available on the [plunker](http://embed.plnkr.co/SYmehtaAnQVyMpLJJY2B/?show=preview) site.

#### VISUAL INTERFACE
On activation, force-horse shows the given graph. The graph stabilizes after a short force simulation. Then, if needed, it **zooms** out, so that the whole graph can be seen at a glance.

On activation, force-horse shows the given graph. The graph stabilizes after a short force simulation. Then, if needed, it **zooms **out, so that the whole graph can be seen at a glance.

Beside showing the graph itself, force-horse provides visual indication of **hovering **over a node/link, and of **selecting **a node/link. It supports node **dragging**, and also **pan **and **zoom**.
Beside showing the graph itself, force-horse provides visual indication of **hovering** over a node/link, and of **selecting** a node/link. It supports node **dragging**, and also **pan** and **zoom**.

In addition, force-horse is providing the following buttons:
* **filter**: remove selected nodes/links from the graph
* **pause/play**: allows to “freeze” the graph, to locate nodes without subsequent changes by the force-layout simulation
* **home**: automatically pan/zoom so that the whole graph can be seen at a glance
* **labels**: show/hide node labels
* **node weight**: show/hide node weight (weightier nodes will be larger)
* **link weight**: show/hide link weight (weightier links will be thicker)
* **link weight**: show/hide link weight (weightier links will be thicker)

#### DEPENDENCIES

The only dependencies of force-horse are:
* **angular.js** v1.4
* **d3.js** v4
The only dependency of force-horse is:
* **d3.js** v4

#### PERFORMANCE

force-horse was designed for high performance. Some of the measures in use are:
* minimal use of angular **$watch**’es
* large graphs are not rendered continuously, but only a few times during the force simulation. The screen rendering is controlled programmatically, implementing javascript**requestAnimationFrame**(). A thin **progress bar** is displayed, during a force simulation, so that even if rendering is held, the user can know the stage and the pace of the current force simulation.
* minimal use of DOM manipulations
* large graphs are not rendered continuously, but only a few times during the force simulation. The screen rendering is controlled programmatically, implementing javascript**requestAnimationFrame**(). A thin **progress bar** is displayed, during a force simulation, so that even if rendering is held, the user can know the stage and the pace of the current force simulation.

#### MULTIPLE LINKS BETWEEN TWO NODES

The ability to compute multiple, parallel link between two nodes is not currently supported intrinsically by d3.js. It was also not yet developed by the users community. Therefore, we developed this ability especially for force-horse. For the mathematical and implementation details, see [here](http://webiks.com/d3-js-force-layout-straight-parallel-links/).
The ability to compute multiple, parallel link between two nodes is not currently supported intrinsically by d3.js. It was also not yet developed by the users community. Therefore, we developed this ability especially for force-horse. For the mathematical and implementation details, see [here](http://webiks.com/d3-js-force-layout-straight-parallel-links/).

#### CONSOLE MESSAGES

Set localStorage.setItem('forceHorse', 'on') to get informative console messages from force-horse.
Set `localStorage.setItem('force-horse', true)` to get informative console messages from force-horse.
To turn it off, remove that item by doing `localStorage.removeItem('force-horse')`
16 changes: 0 additions & 16 deletions bower.json

This file was deleted.

Loading

0 comments on commit 73e7de0

Please sign in to comment.