Browse Source

fixed generation of tx and address relations structure. Improved webapp layout. Not finished addressTree generation algorithm

master
arnaucode 6 years ago
parent
commit
42bfe7cda1
16 changed files with 347 additions and 210 deletions
  1. +18
    -13
      README.md
  2. +3
    -1
      addressTree.go
  3. +3
    -3
      dateAnalysis.go
  4. +36
    -12
      exploreBlockchain.go
  5. +1
    -0
      mongoModels.go
  6. +20
    -2
      serverRoutes.go
  7. +39
    -0
      web/css/style.css
  8. +10
    -33
      web/index.html
  9. +19
    -21
      web/views/addressNetwork/addressNetwork.html
  10. +7
    -9
      web/views/dateAnalysis/dateAnalysis.html
  11. +66
    -48
      web/views/main/main.html
  12. +45
    -18
      web/views/main/main.js
  13. +1
    -1
      web/views/navbar.html
  14. +23
    -25
      web/views/network/network.html
  15. +22
    -24
      web/views/sankey/sankey.html
  16. +34
    -0
      web/views/sidebar.html

+ 18
- 13
README.md

@ -2,21 +2,10 @@
blockchain data analysis, written in Go
![goBlockchainDataAnalysis](https://raw.githubusercontent.com/arnaucode/goBlockchainDataAnalysis/master/goBlockchainDataAnalysis01.png "goBlockchainDataAnalysis")
![goBlockchainDataAnalysis](https://raw.githubusercontent.com/arnaucode/goBlockchainDataAnalysis/master/goBlockchainDataAnalysis02.png "goBlockchainDataAnalysis")
![goBlockchainDataAnalysis](https://raw.githubusercontent.com/arnaucode/goBlockchainDataAnalysis/master/goBlockchainDataAnalysis05.png "goBlockchainDataAnalysis")
![goBlockchainDataAnalysis](https://raw.githubusercontent.com/arnaucode/goBlockchainDataAnalysis/master/goBlockchainDataAnalysis04.png "goBlockchainDataAnalysis")
### Install
1. Nodejs & NPM https://nodejs.org/
1. Nodejs & NPM https://nodejs.org/ --> to serve the web, not necessary if the web files are in a webserver
2. MongoDB https://www.mongodb.com/
3. Faircoin wallet https://download.faircoin.world/
3. Faircoin wallet https://download.faircoin.world/, or the Cryptocurrency desired wallet
4. goBlockchainDataAnalysis https://github.com/arnaucode/goBlockchainDataAnalysis
### Configure
@ -54,6 +43,7 @@ sudo service mongod start
```
./faircoind -txindex -reindex-chainstate
```
Wait until the entire blockchain is downloaded.
3. Run explorer, to fill the database
```
@ -80,3 +70,18 @@ Webapp will run on 127.0.0.1:8080
- Frontend
- AngularJS https://angularjs.org/
- Angular-Bootstrap-Material https://tilwinjoy.github.io/angular-bootstrap-material
### Some screenshots
![goBlockchainDataAnalysis](https://raw.githubusercontent.com/arnaucode/goBlockchainDataAnalysis/master/goBlockchainDataAnalysis05.png "goBlockchainDataAnalysis")
![goBlockchainDataAnalysis](https://raw.githubusercontent.com/arnaucode/goBlockchainDataAnalysis/master/goBlockchainDataAnalysis01.png "goBlockchainDataAnalysis")
![goBlockchainDataAnalysis](https://raw.githubusercontent.com/arnaucode/goBlockchainDataAnalysis/master/goBlockchainDataAnalysis02.png "goBlockchainDataAnalysis")
![goBlockchainDataAnalysis](https://raw.githubusercontent.com/arnaucode/goBlockchainDataAnalysis/master/goBlockchainDataAnalysis04.png "goBlockchainDataAnalysis")

+ 3
- 1
addressTree.go

@ -1,6 +1,8 @@
package main
import (
"fmt"
"gopkg.in/mgo.v2/bson"
)
@ -19,7 +21,6 @@ func upTree(address string, network NetworkModel) NetworkModel {
edges := []EdgeModel{}
err = edgeCollection.Find(bson.M{"to": address}).All(&edges)
check(err)
for _, e := range edges {
if edgeInEdges(network.Edges, e) == false {
network.Edges = append(network.Edges, e)
@ -31,6 +32,7 @@ func upTree(address string, network NetworkModel) NetworkModel {
check(err)
*/
fmt.Println(e.From + " - " + e.To)
if e.From != e.To {
upNetwork = upTree(e.From, network)
for _, upN := range upNetwork.Nodes {

+ 3
- 3
dateAnalysis.go

@ -16,13 +16,13 @@ func timeToDate(blockTime int64) string {
panic(err)
}
tm := time.Unix(i, 0)
fmt.Println(tm)
//fmt.Println(tm)
stringDate := tm.String()
fmt.Println(stringDate)
//fmt.Println(stringDate)
return stringDate
}
func hourAnalysis(e EdgeModel, blockTime int64) {
fmt.Println(blockTime)
//fmt.Println(blockTime)
date := timeToDate(blockTime)
date_hour := strings.Split(date, " ")[1]
hour := strings.Split(date_hour, ":")[0]

+ 36
- 12
exploreBlockchain.go

@ -26,7 +26,7 @@ func explore(client *btcrpcclient.Client, blockHash string) {
block, err := client.GetBlockVerbose(bh)
check(err)
if block.Height > 160 {
if block.Height > 0 {
for k, txHash := range block.Tx {
if k > 0 {
realBlocks++
@ -42,12 +42,25 @@ func explore(client *btcrpcclient.Client, blockHash string) {
tx, err := client.GetRawTransactionVerbose(th)
check(err)
//save Tx
var nTx NodeModel
nTx.Id = txHash
nTx.Label = txHash
nTx.Title = txHash
nTx.Group = strconv.FormatInt(block.Height, 10)
nTx.Value = 1
nTx.Shape = "square"
nTx.Type = "tx"
saveNode(nodeCollection, nTx)
var originAddresses []string
var outputAddresses []string
var outputAmount []float64
for _, Vo := range tx.Vout {
//if Vo.Value > 0 {
for _, outputAddr := range Vo.ScriptPubKey.Addresses {
outputAddresses = append(outputAddresses, outputAddr)
outputAmount = append(outputAmount, Vo.Value)
var n2 NodeModel
n2.Id = outputAddr
n2.Label = outputAddr
@ -55,6 +68,7 @@ func explore(client *btcrpcclient.Client, blockHash string) {
n2.Group = strconv.FormatInt(block.Height, 10)
n2.Value = 1
n2.Shape = "dot"
n2.Type = "address"
saveNode(nodeCollection, n2)
}
//}
@ -71,25 +85,35 @@ func explore(client *btcrpcclient.Client, blockHash string) {
n1.Id = originAddr
n1.Label = originAddr
n1.Title = originAddr
n1.Group = string(block.Height)
n1.Group = strconv.FormatInt(block.Height, 10)
n1.Value = 1
n1.Shape = "dot"
n1.Type = "address"
saveNode(nodeCollection, n1)
for _, outputAddr := range outputAddresses {
var e EdgeModel
e.From = originAddr
e.To = outputAddr
e.Label = txVi.Vout[Vi.Vout].Value
e.Txid = tx.Txid
e.Arrows = "to"
e.BlockHeight = block.Height
saveEdge(edgeCollection, e)
for k, outputAddr := range outputAddresses {
var eIn EdgeModel
eIn.From = originAddr
eIn.To = txHash
eIn.Label = txVi.Vout[Vi.Vout].Value
eIn.Txid = tx.Txid
eIn.Arrows = "to"
eIn.BlockHeight = block.Height
saveEdge(edgeCollection, eIn)
var eOut EdgeModel
eOut.From = txHash
eOut.To = outputAddr
eOut.Label = outputAmount[k]
eOut.Txid = tx.Txid
eOut.Arrows = "to"
eOut.BlockHeight = block.Height
saveEdge(edgeCollection, eOut)
//date analysis
//dateAnalysis(e, tx.Time)
//hour analysis
hourAnalysis(e, tx.Time)
hourAnalysis(eIn, tx.Time)
}
}
} else {

+ 1
- 0
mongoModels.go

@ -22,6 +22,7 @@ type NodeModel struct {
Group string `json:"group"`
Value int `json:"value"`
Shape string `json:"shape"`
Type string `json:"type"`
}
type EdgeModel struct {

+ 20
- 2
serverRoutes.go

@ -26,6 +26,12 @@ var routes = Routes{
"/alladdresses",
AllAddresses,
},
Route{
"GetLastAddr",
"Get",
"/lastaddr",
GetLastAddr,
},
Route{
"GetLastTx",
"Get",
@ -93,7 +99,7 @@ func AllAddresses(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, string(jsonNodes))
}
func GetLastTx(w http.ResponseWriter, r *http.Request) {
func GetLastAddr(w http.ResponseWriter, r *http.Request) {
ipFilter(w, r)
nodes := []NodeModel{}
@ -106,6 +112,19 @@ func GetLastTx(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, string(jNodes))
}
func GetLastTx(w http.ResponseWriter, r *http.Request) {
ipFilter(w, r)
edges := []EdgeModel{}
err := edgeCollection.Find(bson.M{}).Limit(10).Sort("-$natural").All(&edges)
check(err)
//convert []resp struct to json
jsonData, err := json.Marshal(edges)
check(err)
fmt.Fprintln(w, string(jsonData))
}
func AddressNetwork(w http.ResponseWriter, r *http.Request) {
ipFilter(w, r)
@ -125,7 +144,6 @@ func AddressNetwork(w http.ResponseWriter, r *http.Request) {
}
func AddressSankey(w http.ResponseWriter, r *http.Request) {
ipFilter(w, r)
vars := mux.Vars(r)
address := vars["address"]
if address == "undefined" {

+ 39
- 0
web/css/style.css

@ -0,0 +1,39 @@
#mynetwork {
/*background: black;*/
}
.o-height600 {
max-height: 600px!important;
}
.o-height500 {
max-height: 500px!important;
}
.o-height300 {
max-height: 300px!important;
}
.o-overflowScroll {
/*max-height: 600px;*/
overflow-y: scroll;
}
.o-mouseoverGrey {
background: white;
cursor: pointer;
}
.o-mouseoverGrey:hover {
background: #cccccc;
}
/* sidebar */
.o_sidebar a{
color: white;
}
.o_sidebar a:hover{
background: #9E9E9E!important;
color: white;
}

+ 10
- 33
web/index.html

@ -14,48 +14,25 @@
<link rel="stylesheet" href="bower_components/components-font-awesome/css/font-awesome.min.css">
<link href="css/style.css" rel="stylesheet">
<link href="css/colors.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<style type="text/css">
#mynetwork {
/*background: black;*/
}
.o-height600 {
max-height: 600px!important;
}
.o-height500 {
max-height: 500px!important;
}
.o-height300 {
max-height: 300px!important;
}
.o-overflowScroll {
/*max-height: 600px;*/
overflow-y: scroll;
}
.o-mouseoverGrey {
background: white;
cursor: pointer;
}
.o-mouseoverGrey:hover {
background: #cccccc;
}
</style>
</head>
<body ng-app="webApp">
<body ng-app="webApp" style="overflow-x:scroll;">
<div ng-include="'views/navbar.html'"></div>
<div class="row" style="padding-right:10px;">
<div class="col-md-2">
<div ng-include="'views/sidebar.html'"></div>
</div>
<div class="col-md-10">
<div ng-view></div>
</div>
</div>
<div ng-view></div>

+ 19
- 21
web/views/addressNetwork/addressNetwork.html

@ -1,29 +1,27 @@
<div class="container">
<div class="row">
<div class="col-sm-3">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">All addresses</h3>
<div class="row">
<div class="col-sm-3">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">All addresses</h3>
</div>
<div class="panel-body" style="max-height: 500px;overflow-y: scroll;">
<div class="form-group label-floating">
<input ng-model="filterAddress" abmFormControl class="form-control" placeholder="Filter" type="text">
</div>
<div class="panel-body" style="max-height: 500px;overflow-y: scroll;">
<div class="form-group label-floating">
<input ng-model="filterAddress" abmFormControl class="form-control" placeholder="Filter" type="text">
</div>
<div ng-click="getAddressNetwork(node)" class="list-group-item" ng-repeat="node in addresses | filter: filterAddress">
<div class="row-content">
<p class="list-group-item-text">{{node.id}}</p>
<div ng-click="getAddressNetwork(node)" class="list-group-item" ng-repeat="node in addresses | filter: filterAddress">
<div class="row-content">
<p class="list-group-item-text">{{node.id}}</p>
<!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>-->
</div>
<!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>-->
</div>
</div>
</div>
<div class="col-sm-9">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Address history Network Map</h3>
</div>
<div class="panel-body">
<div id="mynetwork" style="height:800px;"></div>
</div>
</div>
<div class="col-sm-9">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Address history Network Map</h3>
</div>
<div class="panel-body">
<div id="mynetwork" style="height:800px;"></div>
</div>
</div>
</div>

+ 7
- 9
web/views/dateAnalysis/dateAnalysis.html

@ -1,13 +1,11 @@
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Tx for each Hour</h3>
</div>
<div class="panel-body">
<canvas id="bar" class="chart chart-bar" chart-data="data" chart-labels="labels">
<div class="row">
<div class="col-md-12">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Tx for each Hour</h3>
</div>
<div class="panel-body">
<canvas id="bar" class="chart chart-bar" chart-data="data" chart-labels="labels">
</canvas>
</div>
</div>
</div>
</div>

+ 66
- 48
web/views/main/main.html

@ -1,57 +1,75 @@
<div class="container">
<div class="row">
<div class="col-sm-4">
<div class="panel">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Last addresses</h3>
</div>
<div class="panel-body" style="max-height: 500px;overflow-y: scroll;">
<div class="list-group-item" ng-repeat="node in addresses">
<div class="row-content">
<p class="list-group-item-text">{{node.id}}</p>
</div>
<div class="row">
<div class="col-sm-4">
<div class="panel">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Last addresses</h3>
</div>
<div class="panel-body" style="max-height: 300px;overflow-y: scroll;">
<div class="list-group-item" ng-repeat="node in addresses">
<div class="row-content">
<p class="list-group-item-text">{{node.id}}</p>
</div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="panel">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Last transactions</h3>
</div>
<div class="panel-body" style="max-height: 500px;overflow-y: scroll;">
<table class="table table-striped table-hover ">
<thead>
<tr>
<th>Hash</th>
<th>From</th>
<th>Date</th>
<th>nºSubtx</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="tx in txs">
<td>
txhash
</td>
<td>{{tx.f}}</td>
<td>{{tx.date}}</td>
<td>{{tx.subtx.length}}</td>
<td><a ng-href="#!/tx/{{tx.id}}">View</a></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-sm-4">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Tx/Hour</h3>
</div>
<div class="panel-body">
<canvas id="line" class="chart chart-line" chart-data="data" chart-labels="labels">
</canvas>
</div>
</div>
<div class="col-sm-4">
<div class="panel">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Other</h3>
</div>
<div class="panel-body">
<canvas id="doughnut" class="chart chart-doughnut" chart-data="data" chart-labels="labels">
</canvas>
</div>
</div>
<div class="col-sm-4">
<div class="panel">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Other</h3>
</div>
<div class="panel-body">
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="panel">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Last Tx with amount</h3>
</div>
<div class="panel-body" style="max-height: 350px;overflow-y: scroll;">
<table class="table table-striped table-hover">
<colgroup>
<col class="col-md-2">
<col class="col-md-2">
<col class="col-md-2">
<col class="col-md-2">
<col class="col-md-2">
<col class="col-md-2">
</colgroup>
<thead>
<tr>
<th>BlockHeight</th>
<th>From</th>
<th>To</th>
<th>Amount</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="tx in txs">
<td>{{tx.blockheight}}</td>
<td style="max-width:100px;overflow-x:hidden;">{{tx.from}}</td>
<td style="max-width:100px;overflow-x:hidden;">{{tx.to}}</td>
<td>{{tx.label}}</td>
<td><a ng-href="#!/tx/{{tx.id}}">View</a></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

+ 45
- 18
web/views/main/main.js

@ -2,22 +2,49 @@
angular.module('app.main', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/main', {
templateUrl: 'views/main/main.html',
controller: 'MainCtrl'
});
}])
.controller('MainCtrl', function($scope, $http) {
$scope.addresses = [];
$http.get(urlapi + 'lasttx')
.then(function(data, status, headers, config) {
console.log('data success');
console.log(data);
$scope.addresses = data.data;
}, function(data, status, headers, config) {
console.log('data error');
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/main', {
templateUrl: 'views/main/main.html',
controller: 'MainCtrl'
});
});
}])
.controller('MainCtrl', function($scope, $http) {
//last addr
$scope.addresses = [];
$http.get(urlapi + 'lastaddr')
.then(function(data, status, headers, config) {
console.log('data success');
console.log(data);
$scope.addresses = data.data;
}, function(data, status, headers, config) {
console.log('data error');
});
//last tx
$scope.txs = [];
$http.get(urlapi + 'lasttx')
.then(function(data, status, headers, config) {
console.log('data success');
console.log(data);
$scope.txs = data.data;
}, function(data, status, headers, config) {
console.log('data error');
});
//date analysis
$scope.data = [];
$scope.labels = [];
$http.get(urlapi + 'houranalysis')
.then(function(data, status, headers, config) {
console.log('data success');
console.log(data);
$scope.data = data.data.data;
$scope.labels = data.data.labels;
}, function(data, status, headers, config) {
console.log('data error');
});
});

+ 1
- 1
web/views/navbar.html

@ -14,7 +14,7 @@
<li><a href="#!/network">Network</a></li>
<li><a href="#!/addressNetwork">Address Network</a></li>
<li><a href="#!/sankey">Sankey diagram</a></li>
<li class="active"><a href="#!/dateAnalysis">Date Analysis</a></li>
<li><a href="#!/dateAnalysis">Date Analysis</a></li>
<li><a href="javascript:void(0)">Timeline</a></li>
</ul>
<form class="navbar-form navbar-left">

+ 23
- 25
web/views/network/network.html

@ -1,32 +1,30 @@
<div class="container">
<div class="row">
<div class="col-sm-3">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Nodes</h3>
</div>
<div class="panel-body" style="max-height: 300px;overflow-y: scroll;">
<div ng-click="focusNode(node)" class="list-group-item" ng-repeat="node in nodes">
<div class="row-content">
<p class="list-group-item-text">{{node.id}}</p>
<div class="row">
<div class="col-sm-3">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Nodes</h3>
</div>
<div class="panel-body" style="max-height: 300px;overflow-y: scroll;">
<div ng-click="focusNode(node)" class="list-group-item" ng-repeat="node in nodes">
<div class="row-content">
<p class="list-group-item-text">{{node.id}}</p>
<!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>-->
</div>
<!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>-->
</div>
</div>
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Selected node</h3>
</div>
<div class="panel-body" style="max-height: 200px;overflow-y: scroll;">
{{selectedNode.nodes}}
</div>
</div>
<div class="col-sm-9">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Network</h3>
</div>
<div class="panel-body">
<div id="mynetwork" style="height:500px;"></div>
</div>
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Selected node</h3>
</div>
<div class="panel-body" style="max-height: 200px;overflow-y: scroll;">
{{selectedNode.nodes}}
</div>
</div>
<div class="col-sm-9">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Network</h3>
</div>
<div class="panel-body">
<div id="mynetwork" style="height:500px;"></div>
</div>
</div>
</div>

+ 22
- 24
web/views/sankey/sankey.html

@ -1,33 +1,31 @@
<div class="container">
<div class="row">
<div class="col-sm-2">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">All addresses</h3>
<div class="row">
<div class="col-sm-2">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">All addresses</h3>
</div>
<div class="panel-body" style="max-height: 500px;overflow-y: scroll;">
<div class="form-group label-floating">
<input ng-model="filterAddress" abmFormControl class="form-control" placeholder="Filter" type="text">
</div>
<div class="panel-body" style="max-height: 500px;overflow-y: scroll;">
<div class="form-group label-floating">
<input ng-model="filterAddress" abmFormControl class="form-control" placeholder="Filter" type="text">
</div>
<div ng-click="getAddressSankey(node)" class="list-group-item" ng-repeat="node in addresses | filter: filterAddress">
<div class="row-content">
<p class="list-group-item-text">{{node.id}}</p>
<div ng-click="getAddressSankey(node)" class="list-group-item" ng-repeat="node in addresses | filter: filterAddress">
<div class="row-content">
<p class="list-group-item-text">{{node.id}}</p>
<!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>-->
</div>
<!--<p class="list-group-item-text">Maecenas sed diam eget risus varius blandit.</p>-->
</div>
</div>
</div>
<div class="col-sm-10">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Sankey - address {{selectedAddress}}</h3>
</div>
<div class="panel-body">
<!--<ng-sankey id="sankeyChart" options="options" data="data"></ng-sankey>
</div>
<div class="col-sm-8">
<div class="panel-heading c_blueGrey300">
<h3 class="panel-title">Sankey - address {{selectedAddress}}</h3>
</div>
<div class="panel-body">
<!--<ng-sankey id="sankeyChart" options="options" data="data"></ng-sankey>
-->
<div id="sankeyChart">
<canvas></canvas>
<svg></svg>
</div>
<div id="sankeyChart">
<canvas></canvas>
<svg></svg>
</div>
</div>
</div>

+ 34
- 0
web/views/sidebar.html

@ -0,0 +1,34 @@
<div class="c_grey600" style="height:800px;margin-top:-20px;">
<ul class="nav o_sidebar">
<li>
<a href="#!/main">
<i class="fa fa-home" aria-hidden="true"></i> Main
</a>
</li>
<li>
<a href="#!/network">
<i class="fa fa-chain" aria-hidden="true"></i> Network
</a>
</li>
<li>
<a href="#!/addressNetwork">
<i class="fa fa-sitemap" aria-hidden="true"></i> Address Network
</a>
</li>
<li>
<a href="#!/sankey">
<i class="fa fa-code-fork" aria-hidden="true"></i> Sankey diagram
</a>
</li>
<li>
<a href="#!/dateAnalysis">
<i class="fa fa-bar-chart" aria-hidden="true"></i> Date Analysis
</a>
</li>
<li>
<a href="javascript:void(0)">
<i class="fa fa-area-chart" aria-hidden="true"></i> Timeline
</a>
</li>
</ul>
</div>

Loading…
Cancel
Save