diff --git a/.gitignore b/.gitignore
index 72a38cea..43956891 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,5 +2,6 @@ bower_components/
node_modules/
/.idea
/build
+/dist
npm-debug.log
/spec/*.js
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 00000000..48dabdee
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,3 @@
+/build
+/bower_components
+*.tgz
diff --git a/CHANGES.md b/CHANGES.md
index 062a71e4..499a16db 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,14 @@
## dev
+## 0.7.0 (unreleased)
+
+Breaking changes
+
+* Polymer elements no longer automatically include the neccesary JS files.
+Instead users must include `dist/the-graph.js`, which bundles the needed JavaScript and provides API under `window.TheGraph`.
+The file is included in `the-graph` NPM packages.
+This is preparation for removing the Polymer dependency, instead providing JS APIs and React components.
+
## 0.6.0 (2017 January 5)
* Add all dependencies besides Polymer to NPM.
diff --git a/Gruntfile.js b/Gruntfile.js
index d6595c0d..5977db51 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -7,7 +7,7 @@
"* Copyright (c) <%= grunt.template.today('yyyy') %> <%= pkg.author.name %>; Licensed <%= _.pluck(pkg.licenses, 'type').join(', ') %> */\n";
var sources = {
- scripts: ['Gruntfile.js', 'the-*/*.js', 'the-*/*.html'],
+ scripts: ['Gruntfile.js', 'the-*/*.js', 'the-*/*.html', 'index.js'],
// elements: ['the-*/*.html'],
stylus: ['themes/*/*.styl'],
css: ['themes/*.css'],
@@ -51,20 +51,20 @@
browserify: {
libs: {
files: {
- 'build/the-graph.js': ['index.js'],
+ 'dist/the-graph.js': ['index.js'],
},
options: {
- transform: ['coffeeify']
- },
- browserifyOptions: {
- require: 'noflo'
+ transform: ['coffeeify'],
+ browserifyOptions: {
+ standalone: 'TheGraph'
+ }
}
}
},
jshint: {
options: {
extract: 'auto',
- strict: true,
+ strict: false,
newcap: false,
"globals": { "Polymer": true }
},
@@ -88,7 +88,7 @@
watch: {
scripts: {
files: sources.scripts,
- tasks: ['jshint:force'],
+ tasks: ['jshint:force', 'browserify:libs'],
options: {
livereload: true
}
diff --git a/examples/demo-full.html b/examples/demo-full.html
index 82d560df..83566861 100644
--- a/examples/demo-full.html
+++ b/examples/demo-full.html
@@ -14,7 +14,7 @@
-
+
diff --git a/examples/demo-simple.html b/examples/demo-simple.html
index 22c20644..26aeff19 100644
--- a/examples/demo-simple.html
+++ b/examples/demo-simple.html
@@ -14,7 +14,7 @@
-
+
diff --git a/examples/demo-thumbnail.html b/examples/demo-thumbnail.html
index 0d8d5541..c7eb36c2 100644
--- a/examples/demo-thumbnail.html
+++ b/examples/demo-thumbnail.html
@@ -4,9 +4,11 @@
the-graph-thumb documentation
-
+
-
+
+
+
diff --git a/index.js b/index.js
index 78ff79c3..162b4b7e 100644
--- a/index.js
+++ b/index.js
@@ -1,2 +1,28 @@
// Build required libs
fbpGraph = require('fbp-graph');
+
+var g = { TheGraph: {} };
+
+require("./the-graph/the-graph.js").register(g);
+require("./the-graph/the-graph-app.js").register(g);
+require("./the-graph/the-graph-graph.js").register(g);
+require("./the-graph/the-graph-node.js").register(g);
+require("./the-graph/the-graph-node-menu.js").register(g);
+require("./the-graph/the-graph-node-menu-port.js").register(g);
+require("./the-graph/the-graph-node-menu-ports.js").register(g);
+require("./the-graph/the-graph-port.js").register(g);
+require("./the-graph/the-graph-edge.js").register(g);
+require("./the-graph/the-graph-iip.js").register(g);
+require("./the-graph/the-graph-group.js").register(g);
+require("./the-graph/the-graph-tooltip.js").register(g);
+require("./the-graph/the-graph-menu.js").register(g);
+require("./the-graph/the-graph-clipboard.js").register(g);
+require("./the-graph/font-awesome-unicode-map.js").register(g);
+
+g.TheGraph.thumb = require('./the-graph-thumb/the-graph-thumb.js');
+g.TheGraph.nav = require('./the-graph-nav/the-graph-nav.js');
+g.TheGraph.autolayout = require('./the-graph/the-graph-autolayout.js');
+g.TheGraph.library = require('./the-graph/the-graph-library.js');
+g.TheGraph.editor = require('./the-graph-editor/the-graph-editor.js');
+
+module.exports = g.TheGraph;
diff --git a/package.json b/package.json
index be66975d..fd596ad0 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"description": "flow-based programming graph editing",
"author": "Forrest Oliphant, the Grid",
"license": "MIT",
- "main": "the-graph-editor/index.html",
+ "main": "index.js",
"dependencies": {
"fbp-graph": "^0.1.0",
"font-awesome": "^4.6.3",
diff --git a/scripts/build-font-awesome-javascript.js b/scripts/build-font-awesome-javascript.js
index f2157477..da5906d4 100644
--- a/scripts/build-font-awesome-javascript.js
+++ b/scripts/build-font-awesome-javascript.js
@@ -26,10 +26,10 @@ var generateFile = function (err, data) {
});
var output = "/*\n this file is generated via `grunt build` \n*/\n\n"+
- "(function (context) {\n"+
- "\"use strict\";\n\n"+
+ "module.exports.register = function (context) {\n"+
+ "\n"+
"context.TheGraph.FONT_AWESOME = "+JSON.stringify(icons, null, 2)+";\n\n"+
- "})(this);";
+ "};";
fs.writeFile(__dirname+'/../the-graph/font-awesome-unicode-map.js', output, function (err) {
if (err) {
@@ -39,4 +39,4 @@ var generateFile = function (err, data) {
});
};
-fs.readFile( __dirname+'/../node_modules/font-awesome/less/variables.less', 'utf8', generateFile );
+fs.readFile( __dirname+'/../node_modules/font-awesome/less/variables.less', 'utf8', generateFile);
diff --git a/spec/runner.html b/spec/runner.html
index c1165210..92a935f9 100644
--- a/spec/runner.html
+++ b/spec/runner.html
@@ -15,7 +15,7 @@
-
+
diff --git a/the-graph-editor/the-graph-editor.html b/the-graph-editor/the-graph-editor.html
index 64b71365..2e61ff22 100644
--- a/the-graph-editor/the-graph-editor.html
+++ b/the-graph-editor/the-graph-editor.html
@@ -44,169 +44,7 @@
forceSelection: false,
created: function () {
this.pan = [0,0];
- var pasteAction = function (graph, itemKey, item) {
- var pasted = TheGraph.Clipboard.paste(graph);
- this.selectedNodes = pasted.nodes;
- this.selectedEdges = [];
- }.bind(this);
- var pasteMenu = {
- icon: "paste",
- iconLabel: "paste",
- action: pasteAction
- };
- // Default context menu defs
-
- var nodeActions = {
- delete: function (graph, itemKey, item) {
- graph.removeNode(itemKey);
- // Remove selection
- var newSelection = [];
- for (var i=0, len=this.selectedNodes.length; ithis.width-x && h>this.height-y) {
- // Hide map
- this.hide = true;
- return;
- } else {
- // Show map
- this.hide = false;
- }
-
- // Clip to bounds
- // Left
- if (x < 0) {
- w += x;
- x = 0;
- this.$.viewrect.style.borderLeftColor = this.viewBoxBorder2;
- } else {
- this.$.viewrect.style.borderLeftColor = this.viewBoxBorder;
- context.fillRect(0, 0, x, this.height);
- }
- // Top
- if (y < 0) {
- h += y;
- y = 0;
- this.$.viewrect.style.borderTopColor = this.viewBoxBorder2;
- } else {
- this.$.viewrect.style.borderTopColor = this.viewBoxBorder;
- context.fillRect(x, 0, w, y);
- }
- // Right
- if (w > this.width-x) {
- w = this.width-x;
- this.$.viewrect.style.borderRightColor = this.viewBoxBorder2;
- } else {
- this.$.viewrect.style.borderRightColor = this.viewBoxBorder;
- context.fillRect(x+w, 0, this.width-(x+w), this.height);
- }
- // Bottom
- if (h > this.height-y) {
- h = this.height-y;
- this.$.viewrect.style.borderBottomColor = this.viewBoxBorder2;
- } else {
- this.$.viewrect.style.borderBottomColor = this.viewBoxBorder;
- context.fillRect(x, y+h, w, this.height-(y+h));
- }
- // Size and translate rect
- this.$.viewrect.style.left = x+"px";
- this.$.viewrect.style.top = y+"px";
- this.$.viewrect.style.width = w+"px";
- this.$.viewrect.style.height = h+"px";
+ var properties = {
+ width: this.width,
+ height: this.height,
+ scale: this.scale,
+ thumbscale: this.thumbscale,
+ thumbrectangle: this.thumbrectangle,
+ viewrectangle: this.viewrectangle,
+ viewBoxBorder: this.viewBoxBorder,
+ viewBoxBorder2: this.viewBoxBorder2,
+ outsideFill: this.outsideFill,
+ };
+ var nav = TheGraph.nav.render(context, this.$.viewrect, properties);
+ this.hide = nav.hide;
// this.scaledviewrectangle = [x, y, w, h];
},
hideChanged: function () {
diff --git a/the-graph-nav/the-graph-nav.js b/the-graph-nav/the-graph-nav.js
new file mode 100644
index 00000000..7c3e0a25
--- /dev/null
+++ b/the-graph-nav/the-graph-nav.js
@@ -0,0 +1,92 @@
+
+function calculateStyleFromTheme(theme) {
+ var style = {};
+ if (theme === "dark") {
+ style.viewBoxBorder = "hsla(190, 100%, 80%, 0.4)";
+ style.viewBoxBorder2 = "hsla( 10, 60%, 32%, 0.3)";
+ style.outsideFill = "hsla(0, 0%, 0%, 0.4)";
+ style.backgroundColor = "hsla(0, 0%, 0%, 0.9)";
+ } else {
+ style.viewBoxBorder = "hsla(190, 100%, 20%, 0.8)";
+ style.viewBoxBorder2 = "hsla( 10, 60%, 80%, 0.8)";
+ style.outsideFill = "hsla(0, 0%, 100%, 0.4)";
+ style.backgroundColor = "hsla(0, 0%, 100%, 0.9)";
+ }
+ return style;
+}
+
+function renderViewRectangle(context, viewrect, props) {
+
+ context.clearRect(0, 0, props.width, props.height);
+ context.fillStyle = props.outsideFill;
+
+ // Scaled view rectangle
+ var x = Math.round( (props.viewrectangle[0]/props.scale - props.thumbrectangle[0]) * props.thumbscale );
+ var y = Math.round( (props.viewrectangle[1]/props.scale - props.thumbrectangle[1]) * props.thumbscale );
+ var w = Math.round( props.viewrectangle[2] * props.thumbscale / props.scale );
+ var h = Math.round( props.viewrectangle[3] * props.thumbscale / props.scale );
+
+ var hide = false;
+ if (x<0 && y<0 && w>props.width-x && h>props.height-y) {
+ // Hide map
+ hide = true;
+ return {
+ hide: hide
+ };
+ } else {
+ // Show map
+ hide = false;
+ }
+
+ // Clip to bounds
+ // Left
+ if (x < 0) {
+ w += x;
+ x = 0;
+ viewrect.style.borderLeftColor = props.viewBoxBorder2;
+ } else {
+ viewrect.style.borderLeftColor = props.viewBoxBorder;
+ context.fillRect(0, 0, x, props.height);
+ }
+ // Top
+ if (y < 0) {
+ h += y;
+ y = 0;
+ viewrect.style.borderTopColor = props.viewBoxBorder2;
+ } else {
+ viewrect.style.borderTopColor = props.viewBoxBorder;
+ context.fillRect(x, 0, w, y);
+ }
+ // Right
+ if (w > props.width-x) {
+ w = props.width-x;
+ viewrect.style.borderRightColor = props.viewBoxBorder2;
+ } else {
+ viewrect.style.borderRightColor = props.viewBoxBorder;
+ context.fillRect(x+w, 0, props.width-(x+w), props.height);
+ }
+ // Bottom
+ if (h > props.height-y) {
+ h = props.height-y;
+ viewrect.style.borderBottomColor = props.viewBoxBorder2;
+ } else {
+ viewrect.style.borderBottomColor = props.viewBoxBorder;
+ context.fillRect(x, y+h, w, props.height-(y+h));
+ }
+
+ // Size and translate rect
+ viewrect.style.left = x+"px";
+ viewrect.style.top = y+"px";
+ viewrect.style.width = w+"px";
+ viewrect.style.height = h+"px";
+
+ return {
+ hide: hide
+ };
+
+}
+
+module.exports = {
+ render: renderViewRectangle,
+ calculateStyleFromTheme: calculateStyleFromTheme,
+};
diff --git a/the-graph-thumb/the-graph-thumb.html b/the-graph-thumb/the-graph-thumb.html
index c02a967e..3623a2bd 100644
--- a/the-graph-thumb/the-graph-thumb.html
+++ b/the-graph-thumb/the-graph-thumb.html
@@ -46,64 +46,13 @@
this.themeChanged();
},
themeChanged: function () {
- if (this.theme === "dark") {
- this.fillStyle = "hsl(184, 8%, 10%)";
- this.strokeStyle = "hsl(180, 11%, 70%)";
- this.edgeColors = [
- "white",
- "hsl( 0, 100%, 46%)",
- "hsl( 35, 100%, 46%)",
- "hsl( 60, 100%, 46%)",
- "hsl(135, 100%, 46%)",
- "hsl(160, 100%, 46%)",
- "hsl(185, 100%, 46%)",
- "hsl(210, 100%, 46%)",
- "hsl(285, 100%, 46%)",
- "hsl(310, 100%, 46%)",
- "hsl(335, 100%, 46%)"
- ];
-
- } else {
- // Light
- this.fillStyle = "hsl(184, 8%, 75%)";
- this.strokeStyle = "hsl(180, 11%, 20%)";
- // Tweaked to make thin lines more visible
- this.edgeColors = [
- "hsl( 0, 0%, 50%)",
- "hsl( 0, 100%, 40%)",
- "hsl( 29, 100%, 40%)",
- "hsl( 47, 100%, 40%)",
- "hsl(138, 100%, 40%)",
- "hsl(160, 73%, 50%)",
- "hsl(181, 100%, 40%)",
- "hsl(216, 100%, 40%)",
- "hsl(260, 100%, 40%)",
- "hsl(348, 100%, 50%)",
- "hsl(328, 100%, 40%)"
- ];
- }
+ var style = TheGraph.thumb.styleFromTheme(this.theme);
+ this.edgeColors = style.edgeColors;
+ this.fillStyle = style.fill;
+ this.strokeStyle = style.stroke;
// Redraw
this.redrawGraph();
},
- drawEdge: function (context, scale, source, target, route) {
- // Draw path
- try {
- context.strokeStyle = this.edgeColors[0];
- if (route) {
- // Color if route defined
- context.strokeStyle = this.edgeColors[route];
- }
- var fromX = Math.round(source.metadata.x*scale)-0.5;
- var fromY = Math.round(source.metadata.y*scale)-0.5;
- var toX = Math.round(target.metadata.x*scale)-0.5;
- var toY = Math.round(target.metadata.y*scale)-0.5;
- context.beginPath();
- context.moveTo(fromX, fromY);
- context.lineTo(toX, toY);
- context.stroke();
- } catch (error) {
- }
- },
redrawGraph: function () {
if (!this.graph) {
return;
@@ -117,149 +66,19 @@
// Need the actual context, not polymer-wrapped one
context = unwrap(context);
- // Reset origin
- context.setTransform(1,0,0,1,0,0);
- // Clear
- context.clearRect(0, 0, this.width, this.height);
- context.lineWidth = this.lineWidth;
- // Find dimensions
- var toDraw = [];
- var minX = Infinity;
- var minY = Infinity;
- var maxX = -Infinity;
- var maxY = -Infinity;
- var nodes = {};
-
- // Process nodes
- this.graph.nodes.forEach(function(process){
- if ( process.metadata && !isNaN(process.metadata.x) && !isNaN(process.metadata.y) ) {
- toDraw.push(process);
- nodes[process.id] = process;
- minX = Math.min(minX, process.metadata.x);
- minY = Math.min(minY, process.metadata.y);
- maxX = Math.max(maxX, process.metadata.x);
- maxY = Math.max(maxY, process.metadata.y);
- }
- }.bind(this));
-
- // Process exported ports
- if (this.graph.inports) {
- Object.keys(this.graph.inports).forEach(function(key){
- var exp = this.graph.inports[key];
- if ( exp.metadata && !isNaN(exp.metadata.x) && !isNaN(exp.metadata.y) ) {
- toDraw.push(exp);
- minX = Math.min(minX, exp.metadata.x);
- minY = Math.min(minY, exp.metadata.y);
- maxX = Math.max(maxX, exp.metadata.x);
- maxY = Math.max(maxY, exp.metadata.y);
- }
- }.bind(this));
- }
- if (this.graph.outports) {
- Object.keys(this.graph.outports).forEach(function(key){
- var exp = this.graph.outports[key];
- if ( exp.metadata && !isNaN(exp.metadata.x) && !isNaN(exp.metadata.y) ) {
- toDraw.push(exp);
- minX = Math.min(minX, exp.metadata.x);
- minY = Math.min(minY, exp.metadata.y);
- maxX = Math.max(maxX, exp.metadata.x);
- maxY = Math.max(maxY, exp.metadata.y);
- }
- }.bind(this));
- }
-
- // Sanity check graph size
- if (!isFinite(minX) || !isFinite(minY) || !isFinite(maxX) || !isFinite(maxY) ) {
- return;
- }
-
- minX -= this.nodeSize;
- minY -= this.nodeSize;
- maxX += this.nodeSize*2;
- maxY += this.nodeSize*2;
- var w = maxX - minX;
- var h = maxY - minY;
- // For the-graph-nav to bind
- this.thumbrectangle[0] = minX;
- this.thumbrectangle[1] = minY;
- this.thumbrectangle[2] = w;
- this.thumbrectangle[3] = h;
- // Scale dimensions
- var scale = (w > h) ? this.width/w : this.height/h;
- this.thumbscale = scale;
- var size = Math.round(this.nodeSize * scale);
- var sizeHalf = size / 2;
- // Translate origin to match
- context.setTransform(1,0,0,1,0-minX*scale,0-minY*scale);
-
- // Draw connection from inports to nodes
- if (this.graph.inports) {
- Object.keys(this.graph.inports).forEach(function(key){
- var exp = this.graph.inports[key];
- if ( exp.metadata && !isNaN(exp.metadata.x) && !isNaN(exp.metadata.y) ) {
- var target = nodes[exp.process];
- if (!target) {
- return;
- }
- this.drawEdge(context, scale, exp, target, 2);
- }
- }.bind(this));
- }
- // Draw connection from nodes to outports
- if (this.graph.outports) {
- Object.keys(this.graph.outports).forEach(function(key){
- var exp = this.graph.outports[key];
- if ( exp.metadata && !isNaN(exp.metadata.x) && !isNaN(exp.metadata.y) ) {
- var source = nodes[exp.process];
- if (!source) {
- return;
- }
- this.drawEdge(context, scale, source, exp, 5);
- }
- }.bind(this));
- }
-
- // Draw edges
- this.graph.edges.forEach(function (connection){
- var source = nodes[connection.from.node];
- var target = nodes[connection.to.node];
- if (!source || !target) {
- return;
- }
- this.drawEdge(context, scale, source, target, connection.metadata.route);
- }.bind(this));
-
- // Draw nodes
- toDraw.forEach(function (node){
- var x = Math.round(node.metadata.x * scale);
- var y = Math.round(node.metadata.y * scale);
-
- // Outer circle
- context.strokeStyle = this.strokeStyle;
- context.fillStyle = this.fillStyle;
- context.beginPath();
- if (node.process && !node.component) {
- context.arc(x, y, sizeHalf / 2, 0, 2*Math.PI, false);
- } else {
- context.arc(x, y, sizeHalf, 0, 2*Math.PI, false);
- }
- context.fill();
- context.stroke();
-
- // Inner circle
- context.beginPath();
- var smallRadius = Math.max(sizeHalf-1.5, 1);
- if (node.process && !node.component) {
- // Exported port
- context.arc(x, y, smallRadius / 2, 0, 2*Math.PI, false);
- } else {
- // Regular node
- context.arc(x, y, smallRadius, 0, 2*Math.PI, false);
- }
- context.fill();
-
- }.bind(this));
-
+ var properties = {
+ width: this.width,
+ height: this.height,
+ edgeColors: this.edgeColors,
+ nodeSize: this.nodeSize,
+ strokeStyle: this.strokeStyle,
+ fillStyle: this.fillStyle,
+ lineWidth: this.lineWidth,
+ };
+ var thumb = TheGraph.thumb.render(context, this.graph, properties);
+
+ this.thumbrectangle = thumb.rectangle;
+ this.thumbscale = thumb.scale;
},
listener: null,
graphChanged: function (oldGraph, newGraph) {
diff --git a/the-graph-thumb/the-graph-thumb.js b/the-graph-thumb/the-graph-thumb.js
new file mode 100644
index 00000000..5487596c
--- /dev/null
+++ b/the-graph-thumb/the-graph-thumb.js
@@ -0,0 +1,220 @@
+
+function drawEdge(context, scale, source, target, route, properties) {
+ // Draw path
+ try {
+ context.strokeStyle = properties.edgeColors[0];
+ if (route) {
+ // Color if route defined
+ context.strokeStyle = properties.edgeColors[route];
+ }
+ var fromX = Math.round(source.metadata.x*scale)-0.5;
+ var fromY = Math.round(source.metadata.y*scale)-0.5;
+ var toX = Math.round(target.metadata.x*scale)-0.5;
+ var toY = Math.round(target.metadata.y*scale)-0.5;
+ context.beginPath();
+ context.moveTo(fromX, fromY);
+ context.lineTo(toX, toY);
+ context.stroke();
+ } catch (error) {
+ // FIXME: handle?
+ }
+}
+
+function styleFromTheme(theme) {
+ var style = {};
+ if (theme === "dark") {
+ style.fill = "hsl(184, 8%, 10%)";
+ style.stroke = "hsl(180, 11%, 70%)";
+ style.edgeColors = [
+ "white",
+ "hsl( 0, 100%, 46%)",
+ "hsl( 35, 100%, 46%)",
+ "hsl( 60, 100%, 46%)",
+ "hsl(135, 100%, 46%)",
+ "hsl(160, 100%, 46%)",
+ "hsl(185, 100%, 46%)",
+ "hsl(210, 100%, 46%)",
+ "hsl(285, 100%, 46%)",
+ "hsl(310, 100%, 46%)",
+ "hsl(335, 100%, 46%)"
+ ];
+
+ } else {
+ // Light
+ style.fill = "hsl(184, 8%, 75%)";
+ style.stroke = "hsl(180, 11%, 20%)";
+ // Tweaked to make thin lines more visible
+ style.edgeColors = [
+ "hsl( 0, 0%, 50%)",
+ "hsl( 0, 100%, 40%)",
+ "hsl( 29, 100%, 40%)",
+ "hsl( 47, 100%, 40%)",
+ "hsl(138, 100%, 40%)",
+ "hsl(160, 73%, 50%)",
+ "hsl(181, 100%, 40%)",
+ "hsl(216, 100%, 40%)",
+ "hsl(260, 100%, 40%)",
+ "hsl(348, 100%, 50%)",
+ "hsl(328, 100%, 40%)"
+ ];
+ }
+ return style;
+}
+
+function renderThumbnail(context, graph, properties) {
+
+ // Reset origin
+ context.setTransform(1,0,0,1,0,0);
+ // Clear
+ context.clearRect(0, 0, properties.width, properties.height);
+ context.lineWidth = properties.lineWidth;
+
+ // Find dimensions
+ var toDraw = [];
+ var minX = Infinity;
+ var minY = Infinity;
+ var maxX = -Infinity;
+ var maxY = -Infinity;
+ var nodes = {};
+
+ // Process nodes
+ graph.nodes.forEach(function(process){
+ if ( process.metadata && !isNaN(process.metadata.x) && !isNaN(process.metadata.y) ) {
+ toDraw.push(process);
+ nodes[process.id] = process;
+ minX = Math.min(minX, process.metadata.x);
+ minY = Math.min(minY, process.metadata.y);
+ maxX = Math.max(maxX, process.metadata.x);
+ maxY = Math.max(maxY, process.metadata.y);
+ }
+ }.bind(this));
+
+ // Process exported ports
+ if (graph.inports) {
+ Object.keys(graph.inports).forEach(function(key){
+ var exp = graph.inports[key];
+ if ( exp.metadata && !isNaN(exp.metadata.x) && !isNaN(exp.metadata.y) ) {
+ toDraw.push(exp);
+ minX = Math.min(minX, exp.metadata.x);
+ minY = Math.min(minY, exp.metadata.y);
+ maxX = Math.max(maxX, exp.metadata.x);
+ maxY = Math.max(maxY, exp.metadata.y);
+ }
+ }.bind(this));
+ }
+ if (graph.outports) {
+ Object.keys(graph.outports).forEach(function(key){
+ var exp = graph.outports[key];
+ if ( exp.metadata && !isNaN(exp.metadata.x) && !isNaN(exp.metadata.y) ) {
+ toDraw.push(exp);
+ minX = Math.min(minX, exp.metadata.x);
+ minY = Math.min(minY, exp.metadata.y);
+ maxX = Math.max(maxX, exp.metadata.x);
+ maxY = Math.max(maxY, exp.metadata.y);
+ }
+ }.bind(this));
+ }
+
+ // Sanity check graph size
+ if (!isFinite(minX) || !isFinite(minY) || !isFinite(maxX) || !isFinite(maxY) ) {
+ return;
+ }
+
+ minX -= properties.nodeSize;
+ minY -= properties.nodeSize;
+ maxX += properties.nodeSize*2;
+ maxY += properties.nodeSize*2;
+ var w = maxX - minX;
+ var h = maxY - minY;
+ // For the-graph-nav to bind
+ var thumbrectangle = [];
+ thumbrectangle[0] = minX;
+ thumbrectangle[1] = minY;
+ thumbrectangle[2] = w;
+ thumbrectangle[3] = h;
+ // Scale dimensions
+ var scale = (w > h) ? properties.width/w : properties.height/h;
+ var thumbscale = scale;
+ var size = Math.round(properties.nodeSize * scale);
+ var sizeHalf = size / 2;
+ // Translate origin to match
+ context.setTransform(1,0,0,1,0-minX*scale,0-minY*scale);
+
+ // Draw connection from inports to nodes
+ if (graph.inports) {
+ Object.keys(graph.inports).forEach(function(key){
+ var exp = graph.inports[key];
+ if ( exp.metadata && !isNaN(exp.metadata.x) && !isNaN(exp.metadata.y) ) {
+ var target = nodes[exp.process];
+ if (!target) {
+ return;
+ }
+ drawEdge(context, scale, exp, target, 2, properties);
+ }
+ }.bind(this));
+ }
+ // Draw connection from nodes to outports
+ if (graph.outports) {
+ Object.keys(graph.outports).forEach(function(key){
+ var exp = graph.outports[key];
+ if ( exp.metadata && !isNaN(exp.metadata.x) && !isNaN(exp.metadata.y) ) {
+ var source = nodes[exp.process];
+ if (!source) {
+ return;
+ }
+ drawEdge(context, scale, source, exp, 5, properties);
+ }
+ }.bind(this));
+ }
+
+ // Draw edges
+ graph.edges.forEach(function (connection){
+ var source = nodes[connection.from.node];
+ var target = nodes[connection.to.node];
+ if (!source || !target) {
+ return;
+ }
+ drawEdge(context, scale, source, target, connection.metadata.route, properties);
+ }.bind(this));
+
+ // Draw nodes
+ toDraw.forEach(function (node){
+ var x = Math.round(node.metadata.x * scale);
+ var y = Math.round(node.metadata.y * scale);
+
+ // Outer circle
+ context.strokeStyle = properties.strokeStyle;
+ context.fillStyle = properties.fillStyle;
+ context.beginPath();
+ if (node.process && !node.component) {
+ context.arc(x, y, sizeHalf / 2, 0, 2*Math.PI, false);
+ } else {
+ context.arc(x, y, sizeHalf, 0, 2*Math.PI, false);
+ }
+ context.fill();
+ context.stroke();
+
+ // Inner circle
+ context.beginPath();
+ var smallRadius = Math.max(sizeHalf-1.5, 1);
+ if (node.process && !node.component) {
+ // Exported port
+ context.arc(x, y, smallRadius / 2, 0, 2*Math.PI, false);
+ } else {
+ // Regular node
+ context.arc(x, y, smallRadius, 0, 2*Math.PI, false);
+ }
+ context.fill();
+
+ }.bind(this));
+
+ return {
+ rectangle: thumbrectangle,
+ scale: thumbscale
+ };
+}
+
+module.exports = {
+ render: renderThumbnail,
+ styleFromTheme: styleFromTheme,
+};
diff --git a/the-graph/font-awesome-unicode-map.js b/the-graph/font-awesome-unicode-map.js
index 586aa99d..5dd8e5c3 100644
--- a/the-graph/font-awesome-unicode-map.js
+++ b/the-graph/font-awesome-unicode-map.js
@@ -2,8 +2,7 @@
this file is generated via `grunt build`
*/
-(function (context) {
-"use strict";
+module.exports.register = function (context) {
context.TheGraph.FONT_AWESOME = {
"500px": "",
@@ -738,4 +737,4 @@ context.TheGraph.FONT_AWESOME = {
"youtube-square": ""
};
-})(this);
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/the-graph/the-graph-app.js b/the-graph/the-graph-app.js
index 9e8a7c9d..653a56c1 100644
--- a/the-graph/the-graph-app.js
+++ b/the-graph/the-graph-app.js
@@ -1,5 +1,4 @@
-(function (context) {
- "use strict";
+module.exports.register = function (context) {
var TheGraph = context.TheGraph;
@@ -625,4 +624,4 @@
}));
-})(this);
+};
diff --git a/the-graph/the-graph-autolayout.js b/the-graph/the-graph-autolayout.js
new file mode 100644
index 00000000..c1aeeddc
--- /dev/null
+++ b/the-graph/the-graph-autolayout.js
@@ -0,0 +1,56 @@
+
+// NOTE: caller should wrap in a graph transaction, to group all changes made to @graph
+function applyAutolayout(graph, keilerGraph, props) {
+
+ // Update original graph nodes with the new coordinates from KIELER graph
+ var children = keilerGraph.children.slice();
+
+ var i, len;
+ for (i=0, len = children.length; i
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-