GoJS是一个实现交互类图表(比如流程图,树图,关系图,力导图等等)的JS库

gojs提供了angular的基本例子,不过是离线版

https://github.com/NorthwoodsSoftware/GoJS/tree/master/projects/angular-basic

下图是运行结果。上面是可拖动的,下面显示当前图表的结构

一。首先完成上面可拖动的部分

diagram-editor

diagram-editor.component.ts

constructor中完成初始化图表的基本属性如颜色等

this.getModel();从服务器获得列表

this.networkService.getModelText().then(r => { console.log(r); this.createModel(JSON.stringify(r)); });

r => { } r是获得的数据,括号里面可以添加对数据进行的操作(可以加函数),我获取数据就是完整的json格式的gojs图表,直接string化传给model它就可以识别了,图表格式如下

{ "class": "go.GraphLinksModel",
"nodeDataArray": [
{"key":1, "text":"Alpha", "color":"lightblue", "loc":"0 0"},
{"key":2, "text":"Beta", "color":"orange", "loc":"72.09912109375 0"},
{"key":3, "text":"Gamma", "color":"lightgreen", "loc":"0 70"},
{"key":4, "text":"Delta", "color":"pink", "loc":"84.40087890625 70"},
{"text":"Gamma", "color":"lightgreen", "key":-3, "loc":"-138.71875 88.41666412353516"},
{"text":"Epsilon", "color":"yellow", "key":-5, "loc":"-316.71875 158.41666412353516"}
],
"linkDataArray": [
{"from":1, "to":2},
{"from":1, "to":3},
{"from":2, "to":2},
{"from":3, "to":4},
{"from":4, "to":1}
]}

然后调用函数createModel,用gojs自带函数go.Model.fromJson显示表格,这样可以实现异步加载图表。

onSave()保存图表到服务器

import { Component, OnInit, ViewChild, ElementRef, Input, Output, EventEmitter, AfterContentInit } from '@angular/core';
import * as go from 'gojs';
import { NetworkService } from '../network.service';
import { Observable } from 'rxjs/observable';
import { catchError, map, tap } from 'rxjs/operators';
import { interval } from 'rxjs/observable/interval';
import {passBoolean} from 'protractor/built/util';
@Component({
selector: 'app-diagram-editor',
templateUrl: './diagram-editor.component.html',
styleUrls: ['./diagram-editor.component.css']
})
export class DiagramEditorComponent implements OnInit {
private diagram: go.Diagram = new go.Diagram();
private palette: go.Palette = new go.Palette(); @ViewChild('diagramDiv')
private diagramRef: ElementRef; @ViewChild('paletteDiv')
private paletteRef: ElementRef; @Input()
get model(): go.Model { return this.diagram.model; }
set model(val: go.Model) { this.diagram.model = val; }
@Output()
nodeSelected = new EventEmitter<go.Node|null>(); @Output()
modelChanged = new EventEmitter<go.ChangedEvent>(); constructor(private networkService: NetworkService) {
this.getModel();
const $ = go.GraphObject.make;
this.diagram = new go.Diagram();
this.diagram.initialContentAlignment = go.Spot.Center;
this.diagram.allowDrop = true; // necessary for dragging from Palette
this.diagram.undoManager.isEnabled = true;
this.diagram.addDiagramListener("ChangedSelection",
e => {
const node = e.diagram.selection.first();
this.nodeSelected.emit(node instanceof go.Node ? node : null);
});
this.diagram.addModelChangedListener(e => e.isTransactionFinished && this.modelChanged.emit(e)); this.diagram.nodeTemplate =
$(go.Node, "Auto",
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape,
{
fill: "white", strokeWidth: 0,
portId: "", cursor: "pointer",
// allow many kinds of links
fromLinkable: true, toLinkable: true,
fromLinkableSelfNode: true, toLinkableSelfNode: true,
fromLinkableDuplicates: true, toLinkableDuplicates: true
},
new go.Binding("fill", "color")),
$(go.TextBlock,
{ margin: 8, editable: true },
new go.Binding("text").makeTwoWay())
); this.diagram.linkTemplate =
$(go.Link,
// allow relinking
{ relinkableFrom: true, relinkableTo: true },
$(go.Shape),
$(go.Shape, { toArrow: "OpenTriangle" })
); this.palette = new go.Palette();
this.palette.nodeTemplateMap = this.diagram.nodeTemplateMap; // initialize contents of Palette
this.palette.model.nodeDataArray =
[
{ text: "Alpha", color: "lightblue" },
{ text: "Beta", color: "orange" },
{ text: "Gamma", color: "lightgreen" },
{ text: "Delta", color: "pink" },
{ text: "Epsilon", color: "yellow" }
];
} ngOnInit() {
this.diagram.div = this.diagramRef.nativeElement;
this.palette.div = this.paletteRef.nativeElement;
}
getModel(): void { this.networkService.getModelText().then(r => { console.log(r); this.createModel(JSON.stringify(r)); }); }
createModel(a: string ): void {
this.model = go.Model.fromJson(a); }
onSave(): void {
this.networkService.saveModel(this.diagram.model.toJson()).subscribe();
} }

diagram-editor.component.html

<div class="diagramsPanel">
<div #paletteDiv class="paletteDiv"></div>
<div #diagramDiv class="diagramDiv"></div>
<div>
<button (click)="onSave()">Save Changes</button>
Diagram Model saved in JSON format:
</div>
<div>
<textarea *ngIf="model" style="width:100%;height:300px">
{{model.toJson()}}
</textarea>
</div>
</div>

二。下半部分显示json字符串:

import { Component, OnInit, ViewChild, ElementRef, Input, Output, EventEmitter } from '@angular/core';
import * as go from 'gojs'; @Component({
selector: 'app-diagram-detail',
templateUrl: './diagram-detail.component.html',
styleUrls: ['./diagram-detail.component.css']
})
export class DiagramDetailComponent implements OnInit {
@Input() node: go.Node;
@Input() data: any;
constructor() { } ngOnInit() {
}
showDetails(node: go.Node | null) {
this.node = node;
if (node) {
// copy the editable properties into a separate Object
this.data = {
text: node.data.text,
color: node.data.color
};
} else {
this.data = null;
}
}
}

diagram-detail.component.html

<div *ngIf="node">
<form *ngIf="node" #form="ngForm" (ngSubmit)="onCommitDetails()">
Node Details:
<div><label>Key: </label>{{node.key}}</div>
<div><label>Text: </label><input [(ngModel)]="data.text" name="text"></div>
<div><label>Color: </label><input [(ngModel)]="data.color" name="color"></div>
<div><label>Location: </label>{{node.location.x.toFixed(2)}}, {{node.location.y.toFixed(2)}}</div>
<div><label># Links: </label>{{node.linksConnected.count}}</div>
</form>
</div>

三。与服务器通信,用了promise,可以实现异步传输,使用rxjs库需要具体说明路径,有部分冗余代码,不懂得可以看看angular官方文档http部分

network.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient, HttpHeaders, HttpClientModule } from '@angular/common/http';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap , retry } from 'rxjs/operators';
import 'rxjs/add/operator/toPromise';
import { MessageService } from './message.service';
import {promise} from 'selenium-webdriver';
const httpOptions = {
//headers: new HttpHeaders({ 'Content-Type': 'application/json' })
headers: new HttpHeaders({'Content-Type': 'application/x-www-form-urlencoded'})
};
@Injectable()
export class NetworkService {
public API = '//localhost:8888';
private getModelUrl = this.API + '/gojs/get'; // URL to web api
private saveModelUrl = this.API + '/gojs/save';
constructor(private http: HttpClient,
private messageService: MessageService) { }
// getModel(): Observable<string> {
// const url = `${this.getModelUrl}`;
// return this.http.get<string>(url).pipe(
// catchError(this.handleError<string>(`getModel`))
// );
// } /** GET: get the model on the server */
getModelText(): Promise<any> {
// The Observable returned by get() is of type Observable<string>
// because a text response was specified.
// There's no need to pass a <string> type parameter to get().
return this.http.get(this.getModelUrl).toPromise().catch(this.handleError());
} /** PUT: update the model on the server */
saveModel (data: string): Observable<any> {
// return this.http.post(this.saveModelUrl, data, httpOptions).pipe(
// catchError(this.handleError<any>('saveModel'))
// );
const body = {model: data};
this.http.post(this.saveModelUrl,
'model=' + data, httpOptions).subscribe(model => {
console.log(data);
});
return null;
} /**
* Handle Http operation that failed.
* Let the app continue.
* @param operation - name of the operation that failed
* @param result - optional value to return as the observable result
*/
private handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => { // TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead // TODO: better job of transforming error for user consumption
this.log(`${operation} failed: ${error.message}`); // Let the app keep running by returning an empty result.
return of(result as T);
};
} /** Log a HeroService message with the MessageService */
private log(message: string) {
this.messageService.add('NetworkService: ' + message);
}
}

message.service.ts没什么大用

import { Injectable } from '@angular/core';

@Injectable()
export class MessageService {
messages: string[] = []; add(message: string) {
this.messages.push(message);
} clear() {
this.messages = [];
}
}

服务器和angular位于不同端口,添加以下代码,否则不允许访问,这里用的服务器是springboot,服务器就比较简单了,不再细说

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration
public class CorsConfig extends WebMvcConfigurerAdapter { @Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.maxAge(3600);
} }

Angular4中利用promise异步加载gojs的更多相关文章

  1. 简单的ListView中item图片异步加载

    前言:     在android开发当中,从目标地址获取图片往往都是采用异步加载的方法.当完全加载完图片后在进行显示,也有些是直接将加载的图片一点一点的显示出来. 这两个区别只是对流的处理不同而已.现 ...

  2. Android中图片的异步加载

    转: 1.  为什么要异步加载图片 下载图片比较费时,先显示文字部分,让加载图片的过程在后台,以提升用户体验 2.  SoftReference的作用 栈内存—引用 堆内存—对象 Eg: Object ...

  3. Android新浪微博客户端(七)——ListView中的图片异步加载、缓存

    原文出自:方杰|http://fangjie.info/?p=193转载请注明出处 最终效果演示:http://fangjie.sinaapp.com/?page_id=54 该项目代码已经放到git ...

  4. vue-awesome-swiper中的数据异步加载

    <template> <div> //第一个轮播 加了v-if 判断,可以实现 loop 轮循 <swiper v-if="gglist.length>1 ...

  5. 小程序中使用ECharts 异步加载数据

    官网例子都是同步的,怎么引入及同步demo请移步官网 <view class="container"> <ec-canvas id="mychart-d ...

  6. Vue中router路由异步加载组件-优化性能

    何时使用异步加载组件 当首页app.js文件太大时,可以拆分组件异步加载,如果app.js文件很小时,不建议使用异步加载组件,因为异步加载组件时每次都要发送一个HTTP请求,这样的代价远比首页一次性加 ...

  7. WinForm中使用BackgroundWorker异步加载数据并使用进度条

    在WinForm程序中,有时会因为加载大量数据导致UI界面假死,这种情况对于用户来说是非常不友好的.因此,在加载大量数据的情况下,首先应该将数据加载放在另一线程中进行,这样保证了UI界面的响应:其次可 ...

  8. 微信小程序中使用ECharts 异步加载数据 实现图表

    <!--pages/bar/index.wxml--> <view class="container"> <ec-canvas id="my ...

  9. MVC4中EasyUI Tree异步加载JSON数据生成树

      1,首先构造tree接受的格式化数据结构MODEL /// <summary> /// 定义EasyUI树的相关数据,方便控制器生成Json数据进行传递 /// </summar ...

随机推荐

  1. sql语句判断 case when用法

    sql语句判断方法之一 selectcase when t.bk1='on' then 1else 0 end  as 基础 ,case when t.bk2='on' then 1else 0 en ...

  2. SpringCloud教程 | 第十一篇: docker部署spring cloud项目

    版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 ,博主地址:http://blog.csdn.net/forezp. http://blog.csdn.net/forezp/art ...

  3. eclipse mars4.5安装hibernate开发环境

    在安装hibernate插件过程中遇到下面前三张图片所示的现象是没关系的,只要最后能看到第四张图的结果就说明安装成功,我一开始不知道走了好多弯路.我用的eclipse mars4.5,采用了在线安装的 ...

  4. 神经网络中的Softmax激活函数

    Softmax回归模型是logistic回归模型在多分类问题上的推广,适用于多分类问题中,且类别之间互斥的场合. Softmax将多个神经元的输出,映射到(0,1)区间内,可以看成是当前输出是属于各个 ...

  5. (十七)js bom/dom

    window 是所有BOM中所有对象的核心. window 的属性 window.self代表自己本身,相当于window. eg: console.log(window.self === windo ...

  6. SHELL 脚本----常用的命令

    一个很不错的bash脚本编写教程,至少没接触过BASH的也能看懂   建立一个脚本 Linux中有好多中不同的shell,但是通常我们使用bash (bourne again shell) 进行she ...

  7. 【Android】SDK工具学习 - adb

    ADB(Android Debug Bridge) 小白笔记 学习资料 adb简要介绍 adb 是一个 C/S 架构的命令行工具,主要由 3 部分组成: 运行在 PC 端的 Client : 可以通过 ...

  8. 如何制作CDLinux启动盘

    用笔记本安装虚拟机并且尝试使用CDLinux系统进行无线密码破解的朋友们可能会遇到很多的问题,今天的经验就是总结了很多的失败然后整理出来的,希望能够对大家有所帮助.本次经验来和大家分享一下使用U盘制作 ...

  9. ASP.NET 线程详解

    本文是博主翻译文章,估计会省略一些,但是我尽量能翻译好,各个知识点通俗易懂.译文如下: ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0 我简 ...

  10. 剑指offer-第五章优化时间和空间效率(把数组排列成最小的数)

    题目:输入一个正整数数组,将所有的数,排列起来,组成一个最小的数.