Skip to content

Commit 721bd04

Browse files
committed
intiated a layout module
1 parent 1259d90 commit 721bd04

File tree

5 files changed

+116
-44
lines changed

5 files changed

+116
-44
lines changed

README.md

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,68 @@ Graph with Physics, No nodes overlap, morph nodes to properties and groups
55
https://networkgraphs.github.io/graphysics/
66

77
# Features
8+
What is already available
9+
* Layout
10+
* stochastic cost driven centrality placement
11+
* Nodes physical collisions, no overlap
12+
* Neighborhood interaction forces
13+
* SVG
14+
* shadows and light filters
15+
* inline html and css with classes
16+
* Mouse and Touch
17+
* Drag Node position with touch
18+
* Context menu (touch empty area, then second touch on Node)
19+
* Hover states with touch Node then touch empty area
820

9-
# Features details
10-
* Update Graph
11-
* startup Demo
12-
* stochastic centrality placement
13-
* Mouse actions
14-
* highlight neighbors
21+
## Features Details
22+
* Node
23+
* hover : highlight neighbors
1524
* drag node
25+
* Node context menu
26+
* pin / unpin
27+
* re-layout pinning current node
1628
* edges
1729
* labels on path
1830

19-
# Features Plan
31+
# Plan
32+
What is planned to be implemented in the Future
33+
* Grouping
34+
* Hierarchical
35+
* cross Grouping
36+
* Swap between :
37+
* proprties
38+
* nodes
39+
* groups
40+
* Properties visualisation
41+
* shape
42+
* color
43+
* light
44+
* filter effect
2045
* Update Graph
21-
* Right click and select samples
2246
* Drag and drop .graphml .Graphson
2347
* Query Gremlin server
24-
* svg full screen
25-
* vertices menu
26-
* context menu
48+
* Global hierarchical context menu
2749
* Mouse actions
2850
* bring neighbors closer
29-
* reference node centrality layout of the whole graph
3051
* reference node / edge Gremlin query
31-
* Swap between :
32-
* proprties
33-
* nodes
34-
* groups
35-
* Hierarchical and cross Grouping
52+
* Performance
53+
* Analysis
54+
* Acceleration (wasm)
3655

37-
## Plan details
56+
## Plan Details
57+
* configure sampling number
58+
* notify edges crossing cost failure
3859
* edges with polylines and arrows
3960
* multi-edges
4061
* graph direction placement left to right for edge labels read
4162

42-
# Development details
43-
* Matter js as physics engine
44-
* svr render base, no update
63+
64+
# Development
65+
* Physics engine : Matter.js
66+
* SVG : Raw, no libraries, only trensparent utils
67+
68+
## Limitations and issues
69+
* centrality algo does not necessarily match neighborhood propagation which could result in cross edges cost inconsistencies
4570

4671
# References
4772
Follow project up from [NetworkGraphs/graph2d](https://github.com/NetworkGraphs/graph2d)
@@ -52,6 +77,10 @@ Follow project up from [NetworkGraphs/graph2d](https://github.com/NetworkGraphs/
5277
* [SVG Animations](https://svgwg.org/specs/animations/)
5378
* [CSS Filters](https://developer.mozilla.org/en-US/docs/Web/CSS/filter)
5479

55-
## Graph javasctipt libraries
80+
## Graph tools and libraries
81+
### Javascript
5682
* [Cytoscape](https://js.cytoscape.org/) : Graph theory (network) library for visualisation and analysis
5783
* [Sigma.js](http://sigmajs.org/) : Sigma is a JavaScript library dedicated to graph drawing. It makes easy to publish networks on Web pages, and allows developers to integrate network exploration in rich Web applications.
84+
### Java
85+
* [Gephi](https://gephi.org/) : State of the art graph editing and analysis, focus on big graphs
86+

src/layout.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { defined } from "../libs/web-js-utils.js";
2+
import {centrality,select_vertex_position} from "./layout/sampling.js"
3+
4+
function remove_add_pinned(g,central_order,already_placed){
5+
for(let [vid,v] of Object.entries(g.vertices)){
6+
if(defined(v.pinned) && v.pinned){
7+
already_placed.push(v)
8+
central_order.splice(central_order.indexOf(v),1)
9+
}
10+
}
11+
}
12+
13+
class Layout{
14+
centrals_first(g,params){
15+
let central_order = centrality(g.vertices)
16+
let already_placed = []
17+
remove_add_pinned(g,central_order,already_placed)
18+
19+
for(let [vid,v] of Object.entries(central_order)){
20+
[v.viewBox.x,v.viewBox.y] = select_vertex_position(v,already_placed,params.width,params.height)//for debug : ,(v.id==6)
21+
already_placed.push(v)
22+
}
23+
}
24+
propagate_neighbors(g,params){
25+
let central_order = centrality(g.vertices)
26+
let already_placed = []
27+
remove_add_pinned(g,central_order,already_placed)
28+
29+
for(let [vid,v] of Object.entries(central_order)){
30+
[v.viewBox.x,v.viewBox.y] = select_vertex_position(v,already_placed,params.width,params.height)//for debug : ,(v.id==6)
31+
already_placed.push(v)
32+
}
33+
}
34+
}
35+
36+
37+
export{Layout};

src/layout/sampling.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ function select_vertex_position(v,placed,width,height,debug=false){
178178
g_debug = debug
179179
let best_index = -1
180180
let best_cost = Number.MAX_VALUE;
181+
let i_costs = []
181182
const nb_samples = 100
182183
let samples = samples_in_rect(nb_samples,width,height,v.viewBox.width,v.viewBox.height)
183184
for(let i=0;i<nb_samples;i++){
@@ -188,6 +189,7 @@ function select_vertex_position(v,placed,width,height,debug=false){
188189
v.viewBox.x = s.x
189190
v.viewBox.y = s.y
190191
const i_cost = interset_cost(v,placed)
192+
i_costs.push(i_cost)
191193
const cost = dist_cost + i_cost
192194
if(debug){
193195
console.log(`total:${cost.toFixed(2)} , dist_cost: ${dist_cost.toFixed(2)} , i_cost:${i_cost}`)
@@ -207,6 +209,14 @@ function select_vertex_position(v,placed,width,height,debug=false){
207209
]
208210
return [x,y]
209211
}else{
212+
//console.log(`best_index for ${v.label} : ${best_index}`)
213+
//let msg = "placed : "
214+
//placed.forEach((p)=>{msg += `${p.label} `})
215+
//console.log(msg)
216+
//console.log(i_costs)
217+
if(i_costs[best_index] == 1){
218+
console.log(`i_cost failed for ${v.label}`)
219+
}
210220
let best_sample = samples[best_index]
211221
v.viewBox.x = best_sample.x
212222
v.viewBox.y = best_sample.y

src/menu.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ function onPointerDown(e){
4545
if(pointer_2 || (!e.target.classList.contains("svg_menu"))){
4646
remove()
4747
}
48-
console.log(e.target.tagName)
4948
}
5049

5150
function onContext(e){

src/physics.js

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {centrality,select_vertex_position} from "./layout/sampling.js"
21
import { defined } from "../libs/web-js-utils.js";
2+
import { Layout } from "./layout.js";
33

44
let g = null;
55
let engine = null;
@@ -8,6 +8,7 @@ let last_run = 0;
88
let last_delta = 0;
99
let drag = {}
1010
let to_run_layout = false
11+
let layout = new Layout()
1112

1213
function get_delta_correction(){
1314
let delta = 1000/60; //used as default for first interations only
@@ -69,35 +70,30 @@ function onMenuAction(e){
6970
if(e.detail.action == "layout"){
7071
e.detail.v.pinned = true
7172
e.detail.v.svg.shape.classList.add("pinned")
72-
layout(false)
73+
layout.propagate_neighbors(g,{width:width,height:height,v:e.detail.v})
74+
place_bodies()
7375
}
7476
}
7577

76-
function layout(create = true){
77-
let central_order = centrality(g.vertices)
78-
let already_placed = []
78+
function create_bodies(){
7979
for(let [vid,v] of Object.entries(g.vertices)){
80-
if(defined(v.pinned) && v.pinned){
81-
already_placed.push(v)
82-
central_order.splice(central_order.indexOf(v),1)
83-
}
80+
v.body = Matter.Bodies.rectangle(v.viewBox.x,v.viewBox.y,v.viewBox.width,v.viewBox.height,
81+
{id:v.id,label:v.label,mass:5,frictionAir:0.3}
82+
)
83+
Matter.World.addBody(engine.world,v.body)
84+
v.viewBox.moved = true
8485
}
85-
86-
for(let [vid,v] of Object.entries(central_order)){
87-
[v.viewBox.x,v.viewBox.y] = select_vertex_position(v,already_placed,width,height)//for debug : ,(v.id==6)
88-
already_placed.push(v)
89-
if(create){
90-
v.body = Matter.Bodies.rectangle(v.viewBox.x,v.viewBox.y,v.viewBox.width,v.viewBox.height,
91-
{id:v.id,label:v.label,mass:5,frictionAir:0.3}
92-
)
93-
Matter.World.addBody(engine.world,v.body)
94-
v.viewBox.moved = true
95-
}else{
86+
}
87+
88+
function place_bodies(){
89+
for(let [vid,v] of Object.entries(g.vertices)){
90+
if(!defined(v.pinned) || !v.pinned){
9691
Matter.Body.setPosition(v.body,Matter.Vector.create(v.viewBox.x,v.viewBox.y))
9792
v.viewBox.moved |= true
9893
}
9994
}
10095
}
96+
10197
class Physics{
10298
constructor(graph_data){
10399
g = graph_data
@@ -111,7 +107,8 @@ class Physics{
111107
create(parent_div){
112108
width = parent_div.offsetWidth
113109
height = parent_div.offsetHeight
114-
layout(true)
110+
layout.centrals_first(g,{width:width,height:height})
111+
create_bodies()
115112
}
116113

117114
run(){

0 commit comments

Comments
 (0)