<!DOCTYPE html>
<html>
<head>
<base href="." />
<link data-require="bootstrap@3.0.0" data-semver="3.0.0" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
<script type="text/javascript" charset="utf-8">
window.AngularVersionForThisPlunker = 'latest'
</script>
<title>angular playground</title>
<link rel="stylesheet" href="style.css" />
<script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js/dist/zone.js"></script>
<script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
<script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
<script src="https://unpkg.com/gojs/release/go-debug.js"></script>
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
<body>
<div class="container">
<my-app>
loading...
</my-app>
</div>
</body>
</html>
/* Styles go here */
var angularVersion;
if(window.AngularVersionForThisPlunker === 'latest'){
angularVersion = ''; //picks up latest
}
else {
angularVersion = '@' + window.AngularVersionForThisPlunker;
}
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
paths: {
'npm:': 'https://unpkg.com/'
},
//map tells the System loader where to look for things
map: {
'app': './src',
'@angular/core': 'npm:@angular/core'+ angularVersion + '/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common' + angularVersion + '/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler' + angularVersion + '/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser' + angularVersion + '/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic' + angularVersion + '/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http' + angularVersion + '/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router' + angularVersion +'/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms' + angularVersion + '/bundles/forms.umd.js',
'@angular/animations': 'npm:@angular/animations' + angularVersion + '/bundles/animations.umd.js',
'@angular/platform-browser/animations': 'npm:@angular/platform-browser' + angularVersion + '/bundles/platform-browser-animations.umd.js',
'@angular/animations/browser': 'npm:@angular/animations' + angularVersion + '/bundles/animations-browser.umd.js',
'@angular/core/testing': 'npm:@angular/core' + angularVersion + '/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common' + angularVersion + '/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler' + angularVersion + '/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser' + angularVersion + '/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic' + angularVersion + '/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http' + angularVersion + '/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router' + angularVersion + '/bundles/router-testing.umd.js',
'tslib': 'npm:tslib@1.6.1',
'rxjs': 'npm:rxjs',
'gojs': 'npm:gojs/release/go-debug.js',
'typescript': 'npm:typescript@2.2.1/lib/typescript.js'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
}
}
});
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
import { NgModule } from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { HttpModule } from '@angular/http'
import { AppComponent } from './app.component'
import { SearchComponent } from './search.component'
import { SearchService } from './search.service'
import { SearchDetailsComponent } from './search-details.component'
import { SearchFilterComponent } from './search-filter.component'
@NgModule({
imports: [ BrowserModule, HttpModule ],
declarations: [ AppComponent, SearchComponent, SearchDetailsComponent, SearchFilterComponent ],
bootstrap: [ AppComponent ],
providers: [SearchService]
})
export class AppModule {}
//our root app component
import { Component } from '@angular/core'
@Component({
selector: 'my-app',
template: `
<div class="row">
<h2>App with {{name}}</h2>
</div>
<div class="col-12">
<search></search>
</div>
`,
})
export class AppComponent {
name:string;
constructor() {
this.name = `GoJS`
}
}
import { Component, OnInit } from '@angular/core'
import { SearchService } from './search.service'
@Component({
selector: 'search',
templateUrl: 'src/app/search.component.html',
styles: [`
ul {
display: inline;
list-style: none
}`]
providers: [SearchService]
})
export class SearchComponent implements OnInit {
opt: any[] = [] // all outputs
showMore: boolean[] = []
visData : object
constructor(private beService: SearchService) {}
ngOnInit(): void {
this.showMore = new Array(this.opt.length)
this.showMore.fill(false)
}
onSearch(input: string) {
if(!input) return;
input = input.trim()
this.beService.firstSearch(input)
.then( res => this.opt.push(res) )
}
getQuery(input: string) {
if(!input) return;
input = input.trim()
// create a JSON query for Backend service
let qTemp = {'concept': encodeURIComponent(input), 'stepRange': 2, 'frozenConcept': 'ddd', 'language': 'en'}
// console.log(JSON.stringify(qTemp))
this.beService.querySearch(qTemp)
.then( res=> this.visData = res)
}
}
/**
* Search BackEnd Service for the App
**/
import { Injectable } from '@angular/core'
import { Http } from '@angular/http'
import 'rxjs/add/operator/toPromise'
@Injectable()
export class SearchService {
// initial search Backend
private searchEndpoint =
'http://hydra2.ikap.biba.uni-bremen.de:8090/detectMeaning/';
private logicalEndpoint =
'http://hydra2.ikap.biba.uni-bremen.de:8090/getLogicalView';
constructor (private http: Http) { }
firstSearch(term: string): Promise<any> {
return this.http.get(`${this.searchEndpoint}?keyword=${term}`)
.toPromise()
.then(res => res.json());
}
querySearch(term: object): Promise<any> {
return this.http.get(`${this.logicalEndpoint}?inputAsJson=${JSON.stringify(term)}`)
.toPromise()
.then( res => res.json());
}
}
<div class="container">
<div class="row input-group">
<input type="text" class="form-control"
#searchVal placeholder="search.."/>
<span class="input-group-btn">
<button class="btn btn-default"
(click)="onSearch(searchVal.value)">Search</button>
</span>
</div>
<p>for test purpose: type <b>company</b>/ <b>contactperson</b>/
<b>highchair</b> (w/o space) above and click the node.
</p>
<p>
Error is visible in the Console Log. Mozilla Firefox <kbd>CTRL</kbd>+<kbd
>SHIFT</kbd>+<kbd>K</kbd>
</p>
<br/>
<br/>
<br/>
<div class="row">
<ul>
<li *ngFor="let eachOp of opt; let outerindex=index">
<div class="btn-group" role="group"
*ngFor="let each of eachOp.conceptOverview; let innerindex=index">
<button class="btn btn-success"
(click)="getQuery(each.url)"
*ngIf="innerindex===0 || showMore[outerIndex]">
{{each['translatedURL']}}
</button>
</div>
<div class="btn-group" style="list-style: none">
<button class="btn btn-default" *ngIf="eachOp.conceptOverview.length > 1"
(click)="showMore[outerIndex]=!showMore[outerIndex]">
{{showMore[outerIndex] ? 'Hide': 'Show'}} Options
</button>
</div>
</li>
</ul>
</div>
</div>
<search-details [config]="visData"></search-details>
import { Component, Input, onChanges,
ViewChild, ElementRef, AfterViewInit } from '@angular/core'
import * as go from 'gojs'
import { RadialLayout } from './layout/RadialLayout'
@Component({
selector: 'search-details',
template: `
<div class="container">
<div class="displayArea" #myDiagramDiv></div>
<div class="row">
<search-filter *ngFor="let each of checkString" [eachFilter]="each"></search-filter>
</div>
</div>`,
styles: [`
.displayArea {
width: 100%;
height: 650px;
}
`]
})
export class SearchDetailsComponent implements onChanges, AfterViewInit {
@Input()
config: object; // visData from parent component
@ViewChild('myDiagramDiv') element: ElementRef
checkString: string[] = [];
const $ = go.GraphObject.make
const myDiagram: go.Diagram
ngOnChanges() {
if (!this.config || this.config.length === 0) return;
// Generate the Radial Graph..
let recApproach = new RecClass();
recApproach.generateGraphRecApproach(this.config, this.myDiagram, this.$);
} // ngOnChanges Ends..
ngAfterViewInit() {
this.myDiagram = this.$(go.Diagram, this.element.nativeElement,
{
initialContentAlignment: go.Spot.Center,
padding: 10,
isReadOnly: true,
'animationManager.isEnabled': false
})
let commonToolTip = this.$(go.Adornment, 'Auto',
{
isShadowed: true
},
this.$(go.Shape, { fill: '#FFFFCC' }),
this.$(go.Panel, 'Vertical',
{
margin: 3
},
this.$(go.TextBlock, // bound to node data
{
margin: 4, font: 'bold 12pt sans-serif'
},
new go.Binding('text')),
this.$(go.TextBlock, // bound to Adornment because of call to Binding.ofObject
new go.Binding('text', '',
(ad) => {
return 'Connections: ' + ad.adornedPart.linksConnected.count;
}).ofObject())
) // end Vertical Panel
) // end Adornment
this.myDiagram.nodeTemplate =
this.$(go.Node, 'Spot',
{
locationSpot: go.Spot.Center,
locationObjectName: 'SHAPE', // Node.location is the center of the Shape
selectionAdorned: true,
click: (e: go.InputEvent, obj: go.GraphObject): void => { this.nodeClicked(e, obj); },
toolTip: commonToolTip
},
this.$(go.Shape, 'Circle',
{
name: 'SHAPE',
fill: 'lightgray', // default value, but also data-bound
stroke: 'transparent',
strokeWidth: 2,
desiredSize: new go.Size(20, 20),
portId: '' // so links will go to the shape, not the whole node
},
new go.Binding('fill', 'color')),
this.$(go.TextBlock,
{
name: 'TEXTBLOCK',
alignment: go.Spot.Right,
alignmentFocus: go.Spot.Left
},
new go.Binding('text'))
)
// this is the root node, at the center of the circular layers
this.myDiagram.nodeTemplateMap.add('Root',
this.$(go.Node, 'Auto',
{
locationSpot: go.Spot.Center,
selectionAdorned: true,
toolTip: commonToolTip
},
this.$(go.Shape, 'Circle',
{ fill: 'white' }),
this.$(go.TextBlock,
{ font: 'bold 12pt sans-serif', margin: 5 },
new go.Binding('text'))
));
// define the Link template
this.myDiagram.linkTemplate =
this.$(go.Link,
{
routing: go.Link.Normal,
curve: go.Link.Bezier,
selectionAdorned: true,
layerName: 'Background'
},
this.$(go.Shape,
{
stroke: 'black', // default value, but is data-bound
strokeWidth: 1
},
new go.Binding('stroke', 'color')
new go.Binding('strokeDashArray', 'dash'))
)
} // ngAfterViewInit Ends..
nodeClicked(e, node): void {
console.log(node.data.text)
this.checkString.push(node.data.text)
} // nodeClicked ends..
}
////////////////// Extreme Complexity below ///////////////////////////////////
////////////////// NO NEED TO LOOK HERE ///////////////////////////////////////
/**
* class OntNode
* A Node structure for Binary Tree of the complete Data obtained from server
*/
class OntNode {
public id: number; // ID of the node
public attr: any[] = []; // Array of all attributes connected to the node
public children: OntNode[] = []; // Check for Nodes with Children
}
/**
* Recursion Class for generating the Graph
*/
class RecClass {
names: string[] = []; // store the Strings from the JSON
/**
* generateGraphRecApproach : Rercusively generate graphs from the incoming JSON config
* @param cnf : Incoming JSON config from Parent Component
* @param myDiagram: Diagram parameter for GoJS
* @param $: Make function for GoJS
*/
public generateGraphRecApproach(cnf: any, myDiagram: any, $: any): void {
// get a Tree structure of the incoming JSON
let linkedOntTree = this.recursionParseJson(cnf);
// console.log('Complete Tree:\n' + JSON.stringify(linkedOntTree)); --> DEBUG
let nodeDataArray: any = []; // Create an Array of Nodes for GoJS.
for (let i = 1; i < this.names.length + 1; i++ ) {
nodeDataArray.push({key: i, text: this.names[i - 1], color: go.Brush.randomColor(128, 240) });
}
// Create The Links to Each node in the Tree with Recursion
let linkDataArray: any = this.recursionLink(linkedOntTree);
// console.log('LinkedDataList: ' + JSON.stringify(linkDataArray)); --> DEBUG
// Diagram Layout..
myDiagram.layout = $(RadialLayout, {
maxLayers: 2,
rotateNode: function(node: any, angle: any, sweep: any, radius: any) {
// rotate the nodes and make sure the text is not upside-down
node.angle = angle;
let label = node.findObject('TEXTBLOCK');
if (label !== null) {
label.angle = ((angle > 90 && angle < 270 || angle < -90) ? 180 : 0);
}
},
commitLayers: function() {
// optional: add circles in the background
// need to remove any old ones first
let diagram = this.diagram;
let gridlayer = diagram.findLayer('Grid');
let circles = new go.Set(go.Part);
gridlayer.parts.each((circle: any) => {
if (circle.name === 'CIRCLE') { circles.add(circle); }
});
circles.each(function(circle) {
diagram.remove(circle);
});
// add circles centered at the root
// let $ = go.GraphObject.make; // for conciseness in defining templates
for (let lay = 1; lay <= this.maxLayers; lay++) {
let radius = lay * this.layerThickness;
let circle =
$(go.Part,
{ name: 'CIRCLE', layerName: 'Grid' },
{ locationSpot: go.Spot.Center, location: this.root.location },
$(go.Shape, 'Circle',
{ width: radius * 2, height: radius * 2 },
{ fill: 'rgba(200,200,200,0.2)', stroke: null }));
diagram.add(circle);
}
}
});
// Use the Lists to Create the Radial Layout...
myDiagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
// For Determining the Root of the Diagram
let centerPoint = nodeDataArray[0];
let rootNode = myDiagram.findNodeForData(centerPoint);
let rootDiagram = rootNode.diagram;
rootNode.category = 'Root';
rootDiagram.layoutDiagram(true);
}
/**
* recursionParseJson: returns a Tree of all the nodes from the JSON data
* @param jsonNode JSON value from the Parent Component
* @returns {OntNode}
*/
private recursionParseJson(jsonNode: any): any {
let node = new OntNode();
// Adding node name
this.names.push(jsonNode['concept']['translatedURL']);
node.id = this.names.length;
// Adding Attributes
for (let eachDatProp of jsonNode.dataproperties) {
this.names.push(eachDatProp.translatedURL);
node.attr.push(this.names.length);
}
// Adding Children
for (let childKey in jsonNode.objectproperties) {
if (jsonNode.objectproperties.hasOwnProperty(childKey)) {
// console.log(childKey); --> DEBUG
node.children.push(this.recursionParseJson(jsonNode.objectproperties[childKey]));
}
}
// console.log('Finished recFunc created node: ' + node.id); --> DEBUG
return node;
}
/**
* recursionLink: Create Links using Recursion for the Tree
* @param linkedOntTree return value from recursionParseJson
* @returns an Array of Link Information
*/
private recursionLink(linkedOntTree: any): any {
let linkedDataArray: any = [];
for (let attr of linkedOntTree.attr) {
linkedDataArray.push({from: linkedOntTree.id, to: attr});
}
for (let child of linkedOntTree.children) {
linkedDataArray.push({from: linkedOntTree.id, to: child.id, dash: [4,4]});
let childrenJson = this.recursionLink(child);
childrenJson.forEach(element => {
linkedDataArray.push(element);
});
}
return linkedDataArray;
}
}
'use strict';
/*
* Copyright (C) 1998-2017 by Northwoods Software Corporation. All Rights Reserved.
*/
import * as go from 'gojs';
/**
* Given a root Node this arranges connected nodes in concentric rings,
* layered by the minimum link distance from the root.
*/
export class RadialLayout extends go.Layout {
private _root: go.Node = null;
private _layerThickness: number = 100; // how thick each ring should be
private _maxLayers: number = Infinity;
/**
* Copies properties to a cloned Layout.
*/
protected cloneProtected(copy: any) {
super.cloneProtected(copy);
// don't copy .root
copy._layerThickness = this._layerThickness;
copy._maxLayers = this._maxLayers;
}
/*
* The Node to act as the root or central node of the radial layout.
*/
get root(): go.Node { return this._root; }
set root(value: go.Node) {
if (this._root !== value) {
this._root = value;
this.invalidateLayout();
}
}
/*
* The thickness of each ring representing a layer.
*/
get layerThickness(): number { return this._layerThickness; }
set layerThickness(value: number) {
if (this._layerThickness !== value) {
this._layerThickness = value;
this.invalidateLayout();
}
}
/*
* The maximum number of layers to be shown, in addition to the root node at layer zero.
* The default value is Infinity.
*/
get maxLayers(): number { return this._maxLayers; }
set maxLayers(value: number) {
if (this._maxLayers !== value) {
this._maxLayers = value;
this.invalidateLayout();
}
}
/**
* Use a LayoutNetwork that always creates RadialVertexes.
*/
public createNetwork () {
let net = new go.LayoutNetwork();
net.createVertex = () => new RadialVertex();
return net;
}
/**
*/
public doLayout(coll: go.Diagram|go.Group|go.Iterable<go.Part>) {
if (this.network === null) {
this.network = this.makeNetwork(coll);
}
if (this.root === null) {
// If no root supplied, choose one without any incoming edges
let it = this.network.vertexes.iterator;
while (it.next()) {
let v = it.value;
if (v.node !== null && v.sourceEdges.count === 0) {
this.root = v.node;
break;
}
}
}
if (this.root === null) {
// If could not find any default root, choose a random one
this.root = this.network.vertexes.first().node;
}
if (this.root === null) {return; } // nothing to do
let rootvert = this.network.findVertex(this.root) as RadialVertex;
if (rootvert === null) {
throw new Error('RadialLayout.root must be a Node in the LayoutNetwork that the RadialLayout is operating on');
}
this.arrangementOrigin = this.initialOrigin(this.arrangementOrigin);
this.findDistances(rootvert);
// sort all results into Arrays of RadialVertexes with the same distance
let verts: any[] = [];
let maxlayer = 0;
let it = this.network.vertexes.iterator;
while (it.next()) {
let vv = it.value as RadialVertex;
vv.laid = false;
let layer = vv.distance;
if (layer === Infinity) {continue; } // Infinity used as init value (set in findDistances())
if (layer > maxlayer) { maxlayer = layer; }
let layerverts: any = verts[layer];
if (layerverts === undefined) {
layerverts = [];
verts[layer] = layerverts;
}
layerverts.push(vv);
}
// now recursively position nodes (using radlay1()), starting with the root
rootvert.centerX = this.arrangementOrigin.x;
rootvert.centerY = this.arrangementOrigin.y;
this.radlay1(rootvert, 1, 0, 360);
// Update the "physical" positions of the nodes and links.
this.updateParts();
this.network = null;
}
/**
* recursively position vertexes in a radial layout
*/
private radlay1(vert: RadialVertex, layer: number, angle: number, sweep: number) {
if (layer > this.maxLayers) {return; } // no need to position nodes outside of maxLayers
let verts: any[] = []; // array of all RadialVertexes connected to 'vert' in layer 'layer'
vert.vertexes.each(function(v: RadialVertex) {
if (v.laid) {return; }
if (v.distance === layer) {verts.push(v); }
});
let found = verts.length;
if (found === 0) {return; }
let radius = layer * this.layerThickness;
let separator = sweep / found; // distance between nodes in their sweep portion
let start = angle - sweep / 2 + separator / 2;
// for each vertex in this layer, place it in its correct layer and position
for (let i = 0; i < found; i++) {
let v = verts[i];
let a = start + i * separator; // the angle to rotate the node to
if (a < 0) {a += 360; } else if (a > 360) {a -= 360; }
// the point to place the node at -- this corresponds with the layer the node is in
// all nodes in the same layer are placed at a constant point, then rotated accordingly
let p = new go.Point(radius, 0);
p.rotate(a);
v.centerX = p.x + this.arrangementOrigin.x;
v.centerY = p.y + this.arrangementOrigin.y;
v.laid = true;
v.angle = a;
v.sweep = separator;
v.radius = radius;
// keep going for all layers
this.radlay1(v, layer + 1, a, sweep / found);
}
}
/**
* Update RadialVertex.distance for every vertex.
*/
private findDistances(source: RadialVertex) {
let diagram = this.diagram;
// keep track of distances from the source node
this.network.vertexes.each(function(v: RadialVertex) { v.distance = Infinity; });
// the source node starts with distance 0
source.distance = 0;
// keep track of nodes for we have set a non-Infinity distance,
// but which we have not yet finished examining
let seen = new go.Set(RadialVertex);
seen.add(source);
// local function for finding a vertex with the smallest distance in a given collection
function leastVertex(coll: any) {
let bestdist = Infinity;
let bestvert: any = null;
let it = coll.iterator;
while (it.next()) {
let v = it.value;
let dist = v.distance;
if (dist < bestdist) {
bestdist = dist;
bestvert = v;
}
}
return bestvert;
}
// keep track of vertexes we have finished examining;
// this avoids unnecessary traversals and helps keep the SEEN collection small
let finished = new go.Set(RadialVertex);
while (seen.count > 0) {
// look at the unfinished vertex with the shortest distance so far
let least = leastVertex(seen);
let leastdist = least.distance;
// by the end of this loop we will have finished examining this LEAST vertex
seen.remove(least);
finished.add(least);
// look at all edges connected with this vertex
least.edges.each(function(e: any) {
let neighbor = e.getOtherVertex(least);
// skip vertexes that we have finished
if (finished.contains(neighbor)) {return; }
let neighbordist = neighbor.distance;
// assume "distance" along a link is unitary, but could be any non-negative number.
let dist = leastdist + 1;
if (dist < neighbordist) {
// if haven't seen that vertex before, add it to the SEEN collection
if (neighbordist === Infinity) {
seen.add(neighbor);
}
// record the new best distance so far to that node
neighbor.distance = dist;
}
});
}
}
/**
* This override positions each Node and also calls {@link #rotateNode}.
*/
commitLayout() {
super.commitLayout();
let it = this.network.vertexes.iterator;
while (it.next()) {
let v = it.value as RadialVertex;
let n = v.node;
if (n !== null) {
n.visible = (v.distance <= this.maxLayers);
this.rotateNode(n, v.angle, v.sweep, v.radius);
}
}
this.commitLayers();
}
/**
* Override this method in order to modify each node as it is laid out.
* By default this method does nothing.
*/
rotateNode(node: go.Node, angle: number, sweep: number, radius: number) {
}
/**
* Override this method in order to create background circles indicating the layers of the radial layout.
* By default this method does nothing.
*/
commitLayers() {
}
} // end RadialLayout
/**
* @ignore
* @constructor
* @extends LayoutVertex
* @class
*/
class RadialVertex extends go.LayoutVertex {
distance: number = Infinity; // number of layers from the root, non-negative integers
laid: boolean = false; // used internally to keep track
angle: number = 0; // the direction at which the node is placed relative to the root node
sweep: number = 0; // the angle subtended by the vertex
radius: number = 0; // the inner radius of the layer containing this vertex
}
import { Component, Input } from '@angular/core';
@Component({
selector: 'search-filter',
template: `<div class="container" style="padding: 25px; margin: 25px; width: 50%;">
<div class="row">{{eachFilter}}</div>
</div>`
})
export class SearchFilterComponent {
@Input() eachFilter: string = 'testfilter'
}