Angular4中利用promise異步加載gojs

GoJS是一個實現交互類圖表(好比流程圖,樹圖,關係圖,力導圖等等)的JS庫css

gojs提供了angular的基本例子,不過是離線版html

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

下圖是運行結果。上面是可拖動的,下面顯示當前圖表的結構git

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

diagram-editorweb

diagram-editor.component.tsspring

constructor中完成初始化圖表的基本屬性如顏色等json

this.getModel();從服務器得到列表api

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

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); } } 
相關文章
相關標籤/搜索