Permalink
  
  
      
      
  
  
    
  
    
  
  
        
          
                
      
        
  
  
  
  
    
    Showing
    
    with
    166 additions
    and 168 deletions.
  
  - +166 −168 Examples/Content/Scripts/helloSpringy.js
 
| @@ -1,213 +1,211 @@ | ||
| /// <reference path="typings/ue.d.ts">/> | ||
| 
     | 
||
| (function (global) { | ||
| "use strict" | ||
| "use strict" | ||
| 
     | 
||
| function GetPC() { | ||
| return PlayerController.C(GWorld.GetAllActorsOfClass(PlayerController).OutActors[0]) | ||
| } | ||
| 
     | 
||
| let Springy = require('springy') | ||
| function GetPC() { | ||
| return PlayerController.C(GWorld.GetAllActorsOfClass(PlayerController).OutActors[0]) | ||
| } | ||
| 
     | 
||
| // Pure ES6 class (not a UClass) | ||
| class SpringyRenderer { | ||
| constructor(graph) { | ||
| this.graph = graph | ||
| let Springy = require('springy') | ||
| 
     | 
||
| // render command to accelerate batched drawing | ||
| this.renderCommands = [] | ||
| // Pure ES6 class (not a UClass) | ||
| class SpringyRenderer { | ||
| constructor(graph) { | ||
| this.graph = graph | ||
| 
     | 
||
| // clear all render commands | ||
| let clear = () => { | ||
| this.renderCommands = [] | ||
| } | ||
| // render command to accelerate batched drawing | ||
| this.renderCommands = [] | ||
| 
     | 
||
| // clear all render commands | ||
| let clear = () => { | ||
| this.renderCommands = [] | ||
| } | ||
| 
     | 
||
| let layout = new Springy.Layout.ForceDirected(this.graph, 400, 400, 0.5) | ||
| let currentBB = layout.getBoundingBox() | ||
| 
     | 
||
| let toScreen = (p) => { | ||
| let size = currentBB.topright.subtract(currentBB.bottomleft) | ||
| let sx = p.subtract(currentBB.bottomleft).divide(size.x).x * 200 + 200 | ||
| let sy = p.subtract(currentBB.bottomleft).divide(size.y).y * 200 + 200 | ||
| return new Springy.Vector(sx,sy) | ||
| } | ||
| let layout = new Springy.Layout.ForceDirected(this.graph, 400, 400, 0.5) | ||
| let currentBB = layout.getBoundingBox() | ||
| 
     | 
||
| let lower = (p) => { | ||
| return {X:p.x,Y:p.y} | ||
| } | ||
| let toScreen = (p) => { | ||
| let size = currentBB.topright.subtract(currentBB.bottomleft) | ||
| let sx = p.subtract(currentBB.bottomleft).divide(size.x).x * 200 + 200 | ||
| let sy = p.subtract(currentBB.bottomleft).divide(size.y).y * 200 + 200 | ||
| return new Springy.Vector(sx,sy) | ||
| } | ||
| 
     | 
||
| let radius = 5 | ||
| let lower = (p) => { | ||
| return {X:p.x,Y:p.y} | ||
| } | ||
| 
     | 
||
| let drawEdge = (edge,p1,p2) => { | ||
| this.renderCommands.push((canvas) => { | ||
| let s1 = toScreen(p1) | ||
| let s2 = toScreen(p2) | ||
| let radius = 5 | ||
| 
     | 
||
| let weight = edge.data.weight || 3 | ||
| let bias = edge.data.bias || 0 | ||
| let drawEdge = (edge,p1,p2) => { | ||
| this.renderCommands.push((canvas) => { | ||
| let s1 = toScreen(p1) | ||
| let s2 = toScreen(p2) | ||
| 
     | 
||
| let direction = new Springy.Vector(s2.x - s1.x, s2.y - s1.y) | ||
| let normal = direction.normalise() | ||
| let perp = normal.normal() | ||
| let weight = edge.data.weight || 3 | ||
| let bias = edge.data.bias || 0 | ||
| 
     | 
||
| if (graph.getEdges(edge.target,edge.source).length > 0) { | ||
| let offset = perp.multiply(3) | ||
| let direction = new Springy.Vector(s2.x - s1.x, s2.y - s1.y) | ||
| let normal = direction.normalise() | ||
| let perp = normal.normal() | ||
| 
     | 
||
| s1 = s1.add(offset) | ||
| s2 = s2.add(offset) | ||
| } | ||
| if (graph.getEdges(edge.target,edge.source).length > 0) { | ||
| let offset = perp.multiply(3) | ||
| 
     | 
||
| let arrow = 4 | ||
| s1 = s1.add(offset) | ||
| s2 = s2.add(offset) | ||
| } | ||
| 
     | 
||
| s1 = s1.add(normal.multiply(radius)) | ||
| s2 = s2.add(normal.multiply(-radius)) | ||
| let arrow = 4 | ||
| 
     | 
||
| let u = {x:perp.x * arrow,y:perp.y * arrow} | ||
| let v = {x:normal.x * arrow,y:normal.y * arrow} | ||
| let s3 = s2.add({x:-u.x-v.x*2,y:-u.y-v.y*2}) | ||
| let s4 = s2.add({x:+u.x-v.x*2,y:+u.y-v.y*2}) | ||
| s1 = s1.add(normal.multiply(radius)) | ||
| s2 = s2.add(normal.multiply(-radius)) | ||
| 
     | 
||
| function gamma(x) { | ||
| var y = {} | ||
| for (var k in x) { | ||
| y[k] = Math.pow(x[k] / 255.0, 2.2) | ||
| } | ||
| return y | ||
| } | ||
| let u = {x:perp.x * arrow,y:perp.y * arrow} | ||
| let v = {x:normal.x * arrow,y:normal.y * arrow} | ||
| let s3 = s2.add({x:-u.x-v.x*2,y:-u.y-v.y*2}) | ||
| let s4 = s2.add({x:+u.x-v.x*2,y:+u.y-v.y*2}) | ||
| 
     | 
||
| function color_from_hex(hex) { | ||
| var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) | ||
| return result ? gamma({ | ||
| R: parseInt(result[1], 16), | ||
| G: parseInt(result[2], 16), | ||
| B: parseInt(result[3], 16), | ||
| A: 255 | ||
| }) : {R:1,G:1,B:1,A:1} | ||
| function gamma(x) { | ||
| var y = {} | ||
| for (var k in x) { | ||
| y[k] = Math.pow(x[k] / 255.0, 2.2) | ||
| } | ||
| 
     | 
||
| let color = color_from_hex(edge.data.color) | ||
| 
     | 
||
| canvas.DrawLine(lower(s1),lower(s2),weight,color) | ||
| canvas.DrawLine(lower(s2),lower(s3),weight,color) | ||
| canvas.DrawLine(lower(s2),lower(s4),weight,color) | ||
| }) | ||
| } | ||
| 
     | 
||
| let size = radius / Math.sqrt(2) * 2 | ||
| let font = GEngine.SmallFont | ||
| 
     | 
||
| let drawNode = (node,p) => { | ||
| this.renderCommands.push((canvas) => { | ||
| let pos = lower(toScreen(p)) | ||
| let size = canvas.ClippedTextSize(font,node.data.label,{X:1,Y:1}) | ||
| size.X += size.Y * 0.7 | ||
| size.Y *= 1.3 | ||
| pos.X -= size.X/2 | ||
| pos.Y -= size.Y/2 | ||
| canvas.DrawTexture(null,pos,size,{},{},{A:0.2},'BLEND_Translucent') | ||
| canvas.DrawText(font,node.data.label,lower(toScreen(p)),{R:1,G:1,B:1,A:1},0,{R:0,G:0,B:0,A:1},{X:1,Y:1},true,true,true,{R:0,G:0,B:0,A:1}) | ||
| }) | ||
| } | ||
| 
     | 
||
| this.renderer = new Springy.Renderer(layout,clear,drawEdge,drawNode) | ||
| } | ||
| 
     | 
||
| init() { | ||
| this.renderer.start() | ||
| return y | ||
| } | ||
| 
     | 
||
| function color_from_hex(hex) { | ||
| var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) | ||
| return result ? gamma({ | ||
| R: parseInt(result[1], 16), | ||
| G: parseInt(result[2], 16), | ||
| B: parseInt(result[3], 16), | ||
| A: 255 | ||
| }) : {R:1,G:1,B:1,A:1} | ||
| } | ||
| 
     | 
||
| let color = color_from_hex(edge.data.color) | ||
| 
     | 
||
| canvas.DrawLine(lower(s1),lower(s2),weight,color) | ||
| canvas.DrawLine(lower(s2),lower(s3),weight,color) | ||
| canvas.DrawLine(lower(s2),lower(s4),weight,color) | ||
| }) | ||
| } | ||
| 
     | 
||
| uninit() { | ||
| this.renderer.stop() | ||
| let size = radius / Math.sqrt(2) * 2 | ||
| let font = GEngine.SmallFont | ||
| 
     | 
||
| let drawNode = (node,p) => { | ||
| this.renderCommands.push((canvas) => { | ||
| let pos = lower(toScreen(p)) | ||
| let size = canvas.ClippedTextSize(font,node.data.label,{X:1,Y:1}) | ||
| size.X += size.Y * 0.7 | ||
| size.Y *= 1.3 | ||
| pos.X -= size.X/2 | ||
| pos.Y -= size.Y/2 | ||
| canvas.DrawTexture(null,pos,size,{},{},{A:0.2},'BLEND_Translucent') | ||
| canvas.DrawText(font,node.data.label,lower(toScreen(p)),{R:1,G:1,B:1,A:1},0,{R:0,G:0,B:0,A:1},{X:1,Y:1},true,true,true,{R:0,G:0,B:0,A:1}) | ||
| }) | ||
| } | ||
| 
     | 
||
| // kick all render commands! | ||
| draw(Canvas) { | ||
| this.renderCommands.forEach((cmd) => cmd(Canvas)) | ||
| } | ||
| this.renderer = new Springy.Renderer(layout,clear,drawEdge,drawNode) | ||
| } | ||
| 
     | 
||
| function setup_graph(graph) { | ||
| graph.addNodes('Dennis', 'Michael', 'Jessica', 'Timothy', 'Barbara') | ||
| graph.addNodes('Amphitryon', 'Alcmene', 'Iphicles', 'Heracles'); | ||
| graph.addEdges( | ||
| ['Dennis', 'Michael', {color: '#00A0B0', label: 'Foo bar'}], | ||
| ['Michael', 'Dennis', {color: '#6A4A3C'}], | ||
| ['Michael', 'Jessica', {color: '#CC333F'}], | ||
| ['Jessica', 'Barbara', {color: '#EB6841'}], | ||
| ['Michael', 'Timothy', {color: '#EDC951'}], | ||
| ['Amphitryon', 'Alcmene', {color: '#7DBE3C'}], | ||
| ['Alcmene', 'Amphitryon', {color: '#BE7D3C'}], | ||
| ['Amphitryon', 'Iphicles'], | ||
| ['Amphitryon', 'Heracles'], | ||
| ['Barbara', 'Timothy', {color: '#6A4A3C'}] | ||
| ); | ||
| init() { | ||
| this.renderer.start() | ||
| } | ||
| 
     | 
||
| function main() { | ||
| let PC = GetPC() | ||
| 
     | 
||
| let UMG = require('UMG') | ||
| uninit() { | ||
| this.renderer.stop() | ||
| } | ||
| 
     | 
||
| // Javascript proxy may be garbage collected at any time. | ||
| // Because our proxy has special member 'renderers', we should | ||
| // keep our proxy not to be gc'ed by holding its reference into | ||
| // global variable 'pool'. | ||
| let pool = [] | ||
| // kick all render commands! | ||
| draw(Canvas) { | ||
| this.renderCommands.forEach((cmd) => cmd(Canvas)) | ||
| } | ||
| } | ||
| 
     | 
||
| function setup_graph(graph) { | ||
| graph.addNodes('Dennis', 'Michael', 'Jessica', 'Timothy', 'Barbara') | ||
| graph.addNodes('Amphitryon', 'Alcmene', 'Iphicles', 'Heracles'); | ||
| graph.addEdges( | ||
| ['Dennis', 'Michael', {color: '#00A0B0', label: 'Foo bar'}], | ||
| ['Michael', 'Dennis', {color: '#6A4A3C'}], | ||
| ['Michael', 'Jessica', {color: '#CC333F'}], | ||
| ['Jessica', 'Barbara', {color: '#EB6841'}], | ||
| ['Michael', 'Timothy', {color: '#EDC951'}], | ||
| ['Amphitryon', 'Alcmene', {color: '#7DBE3C'}], | ||
| ['Alcmene', 'Amphitryon', {color: '#BE7D3C'}], | ||
| ['Amphitryon', 'Iphicles'], | ||
| ['Amphitryon', 'Heracles'], | ||
| ['Barbara', 'Timothy', {color: '#6A4A3C'}] | ||
| ); | ||
| } | ||
| 
     | 
||
| function main() { | ||
| let PC = GetPC() | ||
| 
     | 
||
| let UMG = require('UMG') | ||
| 
     | 
||
| // Javascript proxy may be garbage collected at any time. | ||
| // Because our proxy has special member 'renderers', we should | ||
| // keep our proxy not to be gc'ed by holding its reference into | ||
| // global variable 'pool'. | ||
| let pool = [] | ||
| 
     | 
||
| let Springy = require('springy') | ||
| let graph = new Springy.Graph() | ||
| let Springy = require('springy') | ||
| let graph = new Springy.Graph() | ||
| 
     | 
||
| setup_graph(graph) | ||
| setup_graph(graph) | ||
| 
     | 
||
| // Declare our own HUD class | ||
| class MyHUD extends HUD { | ||
| // init | ||
| ReceiveBeginPlay() { | ||
| // guard this object from V8 GC | ||
| pool.push(this) | ||
| // Declare our own HUD class | ||
| class MyHUD extends HUD { | ||
| // init | ||
| ReceiveBeginPlay() { | ||
| // guard this object from V8 GC | ||
| pool.push(this) | ||
| 
     | 
||
| this.renderers = []; | ||
| this.renderers.push(new SpringyRenderer(graph)) | ||
| this.renderers = []; | ||
| this.renderers.push(new SpringyRenderer(graph)) | ||
| 
     | 
||
| super.ReceiveBeginPlay() | ||
| this.renderers.forEach((r) => r.init && r.init()) | ||
| } | ||
| super.ReceiveBeginPlay() | ||
| this.renderers.forEach((r) => r.init && r.init()) | ||
| } | ||
| 
     | 
||
| // clean up | ||
| ReceiveEndPlay() { | ||
| this.renderers.forEach((r) => r.uninit && r.uninit()) | ||
| super.ReceiveEndPlay() | ||
| } | ||
| // clean up | ||
| ReceiveEndPlay() { | ||
| this.renderers.forEach((r) => r.uninit && r.uninit()) | ||
| super.ReceiveEndPlay() | ||
| } | ||
| 
     | 
||
| // Override drawing function | ||
| ReceiveDrawHUD() { | ||
| super.ReceiveDrawHUD() | ||
| this.renderers.forEach((r) => r.draw(this.Canvas)) | ||
| } | ||
| // Override drawing function | ||
| ReceiveDrawHUD() { | ||
| super.ReceiveDrawHUD() | ||
| this.renderers.forEach((r) => r.draw(this.Canvas)) | ||
| } | ||
| } | ||
| 
     | 
||
| let MyHUD_C = require('uclass')()(global,MyHUD) | ||
| GetPC().ClientSetHUD(MyHUD_C) | ||
| let MyHUD_C = require('uclass')()(global,MyHUD) | ||
| GetPC().ClientSetHUD(MyHUD_C) | ||
| 
     | 
||
| return function () { | ||
| // To destroy our own HUD. | ||
| GetPC().ClientSetHUD(HUD) | ||
| return function () { | ||
| // To destroy our own HUD. | ||
| GetPC().ClientSetHUD(HUD) | ||
| 
     | 
||
| // this sentence keeps 'capture' of pool so that 'pool' will | ||
| // be alive during lifetime 'main'. | ||
| pool = [] | ||
| } | ||
| // this sentence keeps 'capture' of pool so that 'pool' will | ||
| // be alive during lifetime 'main'. | ||
| pool = [] | ||
| } | ||
| } | ||
| 
     | 
||
| try { | ||
| module.exports = () => { | ||
| let cleanup = null | ||
| process.nextTick(() => cleanup = main()); | ||
| return () => cleanup() | ||
| } | ||
| } | ||
| catch (e) { | ||
| require('bootstrap')('helloSpringy') | ||
| try { | ||
| module.exports = () => { | ||
| let cleanup = null | ||
| process.nextTick(() => cleanup = main()); | ||
| return () => cleanup() | ||
| } | ||
| })(this) | ||
| } | ||
| catch (e) { | ||
| require('bootstrap')('helloSpringy') | ||
| } |