Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrating away from AngularJS #16

Merged
merged 26 commits into from
Sep 14, 2017
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
274d4b4
chore(): moving to the main repo
Sep 4, 2017
591d4b4
tests(): add tests for event emitter and buttons
AmitMY Sep 5, 2017
127fc85
tests(): add tests for buttons and main component
AmitMY Sep 6, 2017
5885b06
tests(): add tests for component and provider
AmitMY Sep 6, 2017
0c1de8f
chore(tests): add tests coverage
AmitMY Sep 7, 2017
6825442
docs(blog): add a blog
AmitMY Sep 7, 2017
e643de7
fix(coverage): tests coverage works
AmitMY Sep 7, 2017
2984d1f
fix(buttons): add mask no repeat
AmitMY Sep 10, 2017
af85e91
refactor(): remove the change for options, add a not-DOM intensive se…
AmitMY Sep 10, 2017
4e84769
feat(travis): add travis for release and npm
AmitMY Sep 10, 2017
b213039
fix(travis): use ci script
AmitMY Sep 10, 2017
7a18582
docs(blog): tiny edit
AmitMY Sep 10, 2017
17c3a86
docs(blog): fix footer
AmitMY Sep 10, 2017
01e2231
docs(README): update to current usage
AmitMY Sep 10, 2017
e8f7e43
docs(README): fix formatting
AmitMY Sep 10, 2017
29d0211
docs(README): fix formatting
AmitMY Sep 10, 2017
05bd4e3
docs(): general info
AmitMY Sep 10, 2017
60fde33
fix(component): fix attribute binding
AmitMY Sep 10, 2017
d26020c
docs(BLOG): AngularJS is not deprecated
AmitMY Sep 12, 2017
415a043
docs(BLOG): use custom elements v1
AmitMY Sep 12, 2017
d10fb47
refactor(names): rename files
AmitMY Sep 12, 2017
63fb91c
refactor(): change options to config and data
AmitMY Sep 14, 2017
0f3b239
chore(): bump version
AmitMY Sep 14, 2017
0aaa086
refactor(): rename force-horse-viewer
AmitMY Sep 14, 2017
2f71e07
fix(): moved to viewer
AmitMY Sep 14, 2017
3381b76
refactor(instance): change to viewer
AmitMY Sep 14, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not so familiar with Travis. What does this file do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every commit, travis will automatically try to tests. and report back on github what is the status
If there is a new tag, it will deploy it to a github release, and to an NPM release, hopefully

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below, it shows a PR status

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A very nice blog post and plan. A small point: it seems an exaggeration to call force-horse a "legacy" plugin. It is not that old.. it is just that javascript is developing so fast. I probably wrote it just before ES6 kicked in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
It is legacy, just because AngularJS is legacy, see:

Legacy code refers to an application system source code type that is no longer supported

Yeah, you kind of mixed some ES6 in there, just a bit.

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 deprecated 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small comment: AngularJS is, of course, not the front version of Angular, but it is not deprecated. It will be with us perhaps for a long time still..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AngularJS is not, strictly speaking, deprecated. It is still supported, and widely used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Changed from "deprecated" to "legacy".

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), supported by most modern browsers, or being worked on at this time (In case it isn't supported, there is a tiny [browser polyfill](https://github.com/webcomponents/webcomponentsjs) - see [browsers support](https://caniuse.com/#search=custom%20elements%20v0))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Actually you seem to have used here Custom Elements V1, which is not yet (as of 09.17) supported by most modern browsers.
  2. The link to caniuse.com needs to be fixed (V1)
  3. Can we ship the polyfill inside our package? (and, say, check whether the browser supports custom elements V1, and if not, automatically load the polyfill)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Done
  2. Done
  3. We can, we shan't imo. It is super simple to add, I can add the code to the README, it is like:
  • npm i @webcomponents/custom-elements
  • Add <script src="custom-elements.min.js"></script> or import from '@webcomponents/custom-elements/custom-elements.min.js'

The reason I think we shan't is that if you use Angular or React or whatever, it is just bloat.

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)
109 changes: 70 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,87 @@
# 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>`
## 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 options='{"json": "options"}'></force-horse>
<!-- Angular -->
<force-horse [attr.options]="options | json"></force-horse>
```
From Javascript:
```js
const forceHorse = document.createElement("force-horse");
forceHorse.setOptions(options);
someContainer.appendChild(forceHorse);
```

or:

`<div force-horse options=”ctrl.options”></div>`
To be rendered, force-horse must first get `options`, which can be passed as an attribute, or directly using `setOptions`

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.
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.

# Options parameters
# Options attribute

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:
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:

**data**: the graph data (nodes and links):
```
**data**: the graph 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:
You can use the API by querying the `force-horse` element, and accessing `instance`.

**addEventListener** - accepts an event name (String) and a callback (function). For a list of events see **Events** section below.
# Outputs

Outputs are event emitters. You can subscribe and unsubscribe in the following way:
```
const instance = element.instance;
const subscription = instance.hoverEvent.subscribe(() => { /* some callback */);
subscription.unsubscribe();
```

# Events
These are the current events. PR's and suggestions for more are welcome:
**ready** (`readyEvent`): an SVG is drawn and ready

These are the current events. PR's and suggestiong for more are welcome:
**hover**: a node/link is hovered upon
**hover** (`hoverEvent`): a node/link is hovered upon

**select**: a node/link is selected
**select** (`selectEvent`): a node/link is selected

**dblclick**: a node/link is double-clicked upon
**dblclick** (`doubleClickEvent`): a node/link is double-clicked upon

**filter**: remove the selected nodes/links from the graph
**filter** (`filterEvent`): remove the selected nodes/links from the graph

# 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.
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.

The config parameters are:
```
```js
{
"showLabels": false, //show labels on start
"showNodeWeight": false, // show each node weight or uniform size
Expand All @@ -57,7 +90,6 @@ The config parameters are:
"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,
Expand All @@ -68,38 +100,37 @@ The config parameters are:
}
```

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The demo on plunker is probably out of date

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hahaha probably.
I'll make a new one on the updated code base, as the package is on NPM already (had to test it for the demo)


#### 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