Ver código fonte

Merge pull request #6 from AToMPM/layout-toolbar

Create new layout toolbar, with prototype layout algorithm.
vasco-sousa 7 anos atrás
pai
commit
7c0ce238d0

Diferenças do arquivo suprimidas por serem muito extensas
+ 1309 - 0
client/3rd_party_libs/d3/API.md


Diferenças do arquivo suprimidas por serem muito extensas
+ 1407 - 0
client/3rd_party_libs/d3/CHANGES.md


+ 27 - 0
client/3rd_party_libs/d3/LICENSE

@@ -0,0 +1,27 @@
+Copyright 2010-2017 Mike Bostock
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of contributors may be used to
+  endorse or promote products derived from this software without specific prior
+  written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 57 - 0
client/3rd_party_libs/d3/README.md

@@ -0,0 +1,57 @@
+# D3: Data-Driven Documents
+
+<a href="https://d3js.org"><img src="https://d3js.org/logo.svg" align="left" hspace="10" vspace="6"></a>
+
+**D3** (or **D3.js**) is a JavaScript library for visualizing data using web standards. D3 helps you bring data to life using SVG, Canvas and HTML. D3 combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data.
+
+## Resources
+
+* [API Reference](https://github.com/d3/d3/blob/master/API.md)
+* [Release Notes](https://github.com/d3/d3/releases)
+* [Gallery](https://github.com/d3/d3/wiki/Gallery)
+* [Examples](https://bl.ocks.org/mbostock)
+* [Wiki](https://github.com/d3/d3/wiki)
+
+## Installing
+
+If you use npm, `npm install d3`. Otherwise, download the [latest release](https://github.com/d3/d3/releases/latest). The released bundle supports anonymous AMD, CommonJS, and vanilla environments. You can load directly from [d3js.org](https://d3js.org), [CDNJS](https://cdnjs.com/libraries/d3), or [unpkg](https://unpkg.com/d3/). For example:
+
+```html
+<script src="https://d3js.org/d3.v5.js"></script>
+```
+
+For the minified version:
+
+```html
+<script src="https://d3js.org/d3.v5.min.js"></script>
+```
+
+You can also use the standalone D3 microlibraries. For example, [d3-selection](https://github.com/d3/d3-selection):
+
+```html
+<script src="https://d3js.org/d3-selection.v1.js"></script>
+```
+
+D3 is written using [ES2015 modules](http://www.2ality.com/2014/09/es6-modules-final.html). Create a [custom bundle using Rollup](https://bl.ocks.org/mbostock/bb09af4c39c79cffcde4), Webpack, or your preferred bundler. To import D3 into an ES2015 application, either import specific symbols from specific D3 modules:
+
+```js
+import {scaleLinear} from "d3-scale";
+```
+
+Or import everything into a namespace (here, `d3`):
+
+```js
+import * as d3 from "d3";
+```
+
+In Node:
+
+```js
+var d3 = require("d3");
+```
+
+You can also require individual modules and combine them into a `d3` object using [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign):
+
+```js
+var d3 = Object.assign({}, require("d3-format"), require("d3-geo"), require("d3-geo-projection"));
+```

Diferenças do arquivo suprimidas por serem muito extensas
+ 17787 - 0
client/3rd_party_libs/d3/d3.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 2 - 0
client/3rd_party_libs/d3/d3.min.js


+ 3 - 1
client/atompm.html

@@ -16,7 +16,8 @@
 		<script text="text/javascript" src="client/3rd_party_libs/raphael/plugins/point.js"></script>				
 		<script text="text/javascript" src="client/3rd_party_libs/raphael/plugins/group.js"></script>		
 		<script text="text/javascript" src="client/3rd_party_libs/raphael/plugins/raphael.primitives.js"></script>
-		<script text="text/javascript" src="client/3rd_party_libs/jquery-1.8.2.min.js"></script>	
+		<script text="text/javascript" src="client/3rd_party_libs/jquery-1.8.2.min.js"></script>
+		<script text="text/javascript" src="client/3rd_party_libs/d3/d3.min.js"></script>
         <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
 		<script text="text/javascript" src="client/constants.js"></script>		
 		<script text="text/javascript" src="types.js"></script>		
@@ -42,6 +43,7 @@
 		<script text="text/javascript" src="client/window_management.js"></script>
 		<script text="text/javascript" src="client/query_response.js"></script>
 		<script text="text/javascript" src="client/collaboration.js"></script>
+		<script text="text/javascript" src="client/layout.js"></script>
 		<script text="text/javascript" src="client/client.js"></script>
 		<script text="text/javascript" src="styleinfo.js"></script>
         <link rel="icon" href="favicon.png">

+ 6 - 0
client/client.js

@@ -808,6 +808,12 @@ function __iconToFront(tgt)
 	__icons[__vobj2uri(tgt)]['icon'].toFront();
 }
 
+/*---------------------------- LAYOUT -----------------------------*/
+
+function _autolayout()
+{
+    Layout.autolayout()
+}
 
 /*---------------------------- SELECTION OVERLAY -----------------------------*/
 

+ 1 - 0
client/globalVariables.js

@@ -26,6 +26,7 @@ var DataUtils; /* The Data Utilities object. Handles the loaded objects, edges,
 var EditUtils; /* Handles the Copy, Paste, Undo, and Redo options. Consider merging this with GUIUtils */
 var GeometryUtils; /* Handles transformations and translations. */
 var MMMUtils;
+var Layout; /*For auto-layout capabilities. */
 
 var currentKeys = [];
 

+ 153 - 0
client/layout.js

@@ -0,0 +1,153 @@
+Layout = function(){
+
+
+    this.autolayout = function()
+    {
+
+        //sets for nodes and edges
+        var nodes = [];
+        var links = [];
+
+        //mapping between uris and nodes
+        var nodes2uris = {};
+        var uris2nodes = {};
+
+        //radius between nodes
+        var radius = 0;
+
+        //for computing the centre of the nodes
+        var centreX = 0;
+        var centreY = 0;
+
+        //keep track of the sources and targets for edges
+        //there are edges between nodes and associations
+        var edgeSource = {};
+        var edgeTarget = {};
+
+        var i = 0;
+        for( var uri in __icons ){
+
+            //ignore link iconsmoveEdgeHead
+            var is_link = false;
+            for (var edgeId in __edges){
+                var edgeuri = __edgeId2linkuri(edgeId);
+                if (edgeuri == uri){
+                    is_link = true;
+                    break;
+                }
+            }
+            if (is_link){
+                continue;
+            }
+
+            var icon = __icons[uri]['icon'];
+
+
+            //get x and y, and add to the centre calculation
+            var x = parseFloat(icon.getAttr('__x'));
+            var y = parseFloat(icon.getAttr('__y'));
+
+            centreX = centreX + x;
+            centreY = centreY + y;
+
+            //determine the maximum radius of a node
+            var bbox = icon.getBBox();
+            radius = Math.max(radius, bbox.width, bbox.height);
+
+            //create the node
+            var n = {index: i, x:x, y:y};
+            nodes.push(n);
+
+            //keep the mapping
+            nodes2uris[n.index] = uri;
+            uris2nodes[uri] = n.index;
+
+            i = i + 1;
+        }
+
+        //find centre of the nodes for the layout
+        centreX = centreX / nodes.length;
+        centreY = centreY / nodes.length;
+
+
+        //create the edges
+        for (var edge in __edges){
+
+        	var start = __edges[edge]['start'];
+        	var end = __edges[edge]['end'];
+
+        	var source = uris2nodes[start];
+        	var target = uris2nodes[end];
+
+            //associations are composed of two edges
+            //so record the node IDs at either end
+            //TODO: Replaceable with var linkIn = __edgeId2ends(edgeId)[0];?
+        	if (source == undefined){
+        	    edgeTarget[start] = target;
+            }
+
+        	if (target == undefined){
+        	    edgeSource[end] = source;
+            }
+        }
+
+        //for each association, create the link in the force graph
+        for (var assoc in edgeSource) {
+
+            var s = edgeSource[assoc];
+            var t = edgeTarget[assoc];
+
+            links.push({source: s, target: t})
+        }
+
+
+        //init the simulation
+        var simulation = d3.forceSimulation(nodes)
+            .force("charge", d3.forceManyBody().strength(10))
+            .force("link", d3.forceLink(links).distance(20).strength(1).iterations(10))
+        	.force("collide", d3.forceCollide(radius))
+            .force("center", d3.forceCenter(centreX, centreY))
+            ;
+
+        //stop the simulation (as we're not visualizing it)
+        simulation.stop();
+
+        //progress the simulation
+        for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) {
+            simulation.tick();
+        }
+
+        for (var i = 0; i < nodes.length; i++){
+
+            var n = nodes[i];
+            var uri = nodes2uris[n.index];
+
+
+            var icon = __icons[uri]['icon'];
+            var bbox = icon.getBBox();
+
+            //restrict to stay in the canvas
+            var x = (n.x > bbox.width)?n.x:bbox.width;
+            var y = (n.y > bbox.height)?n.y:bbox.height;
+
+            //move each icon
+            //TODO: should move edges as well,
+            //but moving the two nodes at each end of the edge
+            //double moves the edge ends, with one overwriting
+            //the other.
+            //would have to break apart
+            //functions in geometry_utils or query_response to be
+            //able to move ends of edges independently
+            __select([uri]);
+            GeometryUtils.initSelectionTransformationPreviewOverlay(bbox.x,bbox.y);
+		    GeometryUtils.previewSelectionTranslation(x, y);
+		    GeometryUtils.transformSelection();
+
+		    GeometryUtils.hideTransformationPreviewOverlay();
+		    __select();
+        }
+
+     };
+
+    return this;
+}();

+ 219 - 0
users/(default)/Toolbars/Layout/Layout.buttons.model

@@ -0,0 +1,219 @@
+{
+	"csm": {
+		"nodes": {
+			"0": {
+				"typename": {
+					"type": "string",
+					"value": "ButtonIcon"
+				},
+				"position": {
+					"type": "list<double>",
+					"value": [
+						472,
+						159
+					]
+				},
+				"orientation": {
+					"type": "double",
+					"value": 0
+				},
+				"scale": {
+					"type": "list<double>",
+					"value": [
+						1,
+						1
+					]
+				},
+				"mapper": {
+					"type": "code",
+					"value": ""
+				},
+				"parser": {
+					"type": "code",
+					"value": ""
+				},
+				"$contents": {
+					"type": "map<string,*>",
+					"value": {
+						"nodes": {
+							"1": {
+								"width": {
+									"type": "double",
+									"value": "120"
+								},
+								"height": {
+									"type": "double",
+									"value": "50"
+								},
+								"cornerRadius": {
+									"type": "double",
+									"value": "25"
+								},
+								"style": {
+									"type": "map<string,string>",
+									"value": {
+										"stroke": "#af0000",
+										"stroke-dasharray": "",
+										"fill": "#000000",
+										"fill-opacity": 0.05,
+										"stroke-width": 2
+									}
+								},
+								"mapper": {
+									"type": "code",
+									"value": ""
+								},
+								"parser": {
+									"type": "code",
+									"value": ""
+								},
+								"$type": "/Formalisms/__LanguageSyntax__/ConcreteSyntax/ConcreteSyntax/Rectangle",
+								"position": {
+									"type": "list<double>",
+									"value": [
+										0,
+										0
+									]
+								},
+								"orientation": {
+									"type": "double",
+									"value": 0
+								},
+								"scale": {
+									"type": "list<double>",
+									"value": [
+										1,
+										1
+									]
+								}
+							},
+							"2": {
+								"textContent": {
+									"type": "string",
+									"value": "layout"
+								},
+								"style": {
+									"type": "map<string,string>",
+									"value": {
+										"stroke": "#000000",
+										"stroke-dasharray": "",
+										"fill": "#ffffff",
+										"fill-opacity": 0.75,
+										"font-size": "13px",
+										"stroke-width": 1
+									}
+								},
+								"mapper": {
+									"type": "code",
+									"value": "({\"textContent\":getAttr(\"name\")})"
+								},
+								"parser": {
+									"type": "code",
+									"value": "({\"name\":getAttr(\"textContent\")})"
+								},
+								"$type": "/Formalisms/__LanguageSyntax__/ConcreteSyntax/ConcreteSyntax/Text",
+								"position": {
+									"type": "list<double>",
+									"value": [
+										10,
+										13
+									]
+								},
+								"orientation": {
+									"type": "double",
+									"value": 0
+								},
+								"scale": {
+									"type": "list<double>",
+									"value": [
+										1,
+										1
+									]
+								}
+							},
+							"3": {
+								"$type": "/Formalisms/__LanguageSyntax__/ConcreteSyntax/ConcreteSyntax/Contain",
+								"position": {
+									"type": "list<double>",
+									"value": [
+										17.74899850809561,
+										12.998998508095553
+									]
+								},
+								"orientation": {
+									"type": "double",
+									"value": 0
+								},
+								"scale": {
+									"type": "list<double>",
+									"value": [
+										1,
+										1
+									]
+								},
+								"link-style": {
+									"type": "map<string,string>",
+									"value": {
+										"stroke": "#00ffff",
+										"stroke-dasharray": "",
+										"stroke-opacity": 0.1,
+										"arrow-start": "none",
+										"arrow-end": "classic-wide-long"
+									}
+								}
+							}
+						},
+						"edges": [
+							{
+								"src": "1",
+								"dest": 3
+							},
+							{
+								"src": 3,
+								"dest": "2"
+							}
+						]
+					}
+				},
+				"$asuri": {
+					"type": "string",
+					"value": "/Formalisms/__Utilities__/Buttons/Buttons/Button/0.instance"
+				},
+				"$type": "/Formalisms/__Utilities__/Buttons/Buttons.defaultIcons/ButtonIcon"
+			}
+		},
+		"edges": [],
+		"metamodels": [
+			"/Formalisms/__Utilities__/Buttons/Buttons.defaultIcons",
+			"/Formalisms/__LanguageSyntax__/ConcreteSyntax/ConcreteSyntax.defaultIcons",
+			"/Formalisms/__LanguageSyntax__/SimpleClassDiagram/SimpleClassDiagram.defaultIcons",
+			"/Formalisms/SCCD/SCCD.defaultIcons"
+		]
+	},
+	"asm": {
+		"nodes": {
+			"0": {
+				"name": {
+					"type": "string",
+					"value": "layout"
+				},
+				"tooltip": {
+					"type": "string",
+					"value": "EXPERIMENTAL - Try to lay the model out automatically"
+				},
+				"code": {
+					"type": "code",
+					"value": "_autolayout()\n"
+				},
+				"$type": "/Formalisms/__Utilities__/Buttons/Buttons/Button"
+			}
+		},
+		"edges": [],
+		"metamodels": [
+			"/Formalisms/__Utilities__/Buttons/Buttons",
+			"/Formalisms/__LanguageSyntax__/ConcreteSyntax/ConcreteSyntax",
+			"/Formalisms/__LanguageSyntax__/SimpleClassDiagram/SimpleClassDiagram",
+			"/Formalisms/SCCD/SCCD"
+		]
+	}
+}

BIN
users/(default)/Toolbars/Layout/layout.icon.png