如何将mxGraph与Angular 4集成?

时间:2018-04-19 13:45:45

标签: angular angular-cli typescript-typings mxgraph

我正在研究Angular 4,我想在我的项目中集成mxGraph。 我已经google了,但我没有得到完整的工作示例。

我尝试过以下方式,但它也不适用于我。

我遵循的步骤:

  1. 已安装的mxgraph:npm install mxgraph --save

    mxgraph的npm包:https://www.npmjs.com/package/mxgraph

  2. 已安装的mxgraph-typings:npm install lgleim/mxgraph-typings --save

    mxgraph-typings的Github Repo - https://github.com/lgleim/mxgraph-typings

  3. 现在我已将其导入我的组件:import {mxgraph} from 'mxgraph';

  4. 在.angular-cli.json资产数组中添加以下行,以使mxGraph资产可用。

    {"glob":"**/*", "input":"node_modules/mxgraph/javascript/src", "output": "./mxgraph"}
    
  5. 如果我尝试使用它:const graph: mxgraph.mxGraph = new mxgraph.mxGraph(document.getElementById('graphContainer'));

    当我运行ng serve

    然后我得到问题/错误,如:
    Module not found: Error: Can't resolve 'mxgraph' in 'path to my file where I have imported and used mxgraph'

  6. 现在,如果我尝试设置mxBasePath:

    const mx = require('mxgraph')({
      mxImageBasePath: 'mxgraph/images',
      mxBasePath: 'mxgraph'
    });
    

    并像这样使用:

    const graph: mxgraph.mxGraph = mx.mxGraph(document.getElementById('graphContainer'));

    当我运行ng serve

    这次我也遇到同样的问题/错误:
    Module not found: Error: Can't resolve 'mxgraph' in 'path to my file where I have imported and used mxgraph'

  7. 有人知道我在这里缺少什么吗?或者为什么不起作用?

    如果有人知道将mxGraph与Angular 4集成的其他/更好方法,请告诉我。

    先谢谢!!

5 个答案:

答案 0 :(得分:2)

我遇到了完全相同的问题。根据“ lgleim”的说法,问题出在mxgraph npm软件包上。问题在这里讨论:https://github.com/jgraph/mxgraph/issues/169

我无法解决上述问题。但是,通过遵循本文,我成功地将mxgraph与angular 7集成在一起:https://itnext.io/how-to-integrate-mxgraph-with-angular-6-18c3a2bb8566

第1步

首先安装最新版本的mxgraph:

npm install mxgraph

第2步

然后从https://github.com/gooddaytoday/mxgraph-typescript-definitions.git下载输入内容。将文件提取到角度项目的“ src”文件夹中

第3步

在您的angular.json文件中,添加以下内容:

  1. 在资产数组中添加:

    {“ glob”:“ ** / *”,“ input”:“ src / assets /”,“ output”:“ / assets /”},

    {“ glob”:“ ** / *”,“ input”:“ ./node_modules/mxgraph/javascript/src”,“ output”:“ / assets / mxgraph”}

  2. 在脚本数组中添加:

    “ node_modules / mxgraph / javascript / mxClient.js”

有两个脚本和资产数组。一次进入“构建”阶段,一次进入“测试”阶段。两者都添加。

完成所有操作后,您就可以开始了。 :)

示例代码:

component.html:

<div #graphContainer id="graphContainer"></div>

component.ts

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
declare var mxPerimeter: any;
declare var mxConstants: any;

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {

  @ViewChild('graphContainer') graphContainer: ElementRef;
  graph: mxGraph;

  ngAfterViewInit() {
    this.graph = new mxGraph(this.graphContainer.nativeElement);

    // set default styles for graph
    const style = this.graph.getStylesheet().getDefaultVertexStyle();
    style[mxConstants.STYLE_PERIMETER] = mxPerimeter.EllipsePerimeter;
    style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_ELLIPSE;
    style[mxConstants.DEFAULT_VALID_COLOR] = '#00FF00';
    this.graph.getStylesheet().putDefaultVertexStyle (style);

    // add cells
    try {
      const parent = this.graph.getDefaultParent();
      this.graph.getModel().beginUpdate();
      const vertex1 = this.graph.insertVertex(parent, '1', 'Vertex 1', 0, 0, 200, 80);
      const vertex2 = this.graph.insertVertex(parent, '2', 'Vertex 2', 0, 0, 200, 80);
      this.graph.insertEdge(parent, '', '', vertex1, vertex2);
    } finally {
      this.graph.getModel().endUpdate();
      new mxHierarchicalLayout(this.graph).execute(this.graph.getDefaultParent());
    }
  }

}

请注意,我已经使用了声明语句来声明 mxPerimeter mxConstants 。原因是类型定义不完整。因此,我必须自己声明一些类名称。这只是一点小技巧,可以避免编译器错误。通过使用声明语句,我实际上是在告诉编译器允许此类。但是,它不能帮助各种文本编辑器使用智能提示。

答案 1 :(得分:1)

如果有人仍在努力与Angular 4/5/6中的mxGraph集成进行斗争。这是完整的解决方案:

有关不同mxGraph存储库的一些详细信息:

Repo-1: https://github.com/jgraph/mxgraph
        This is an official release repo of mxGraph. With npm issues.

Repo-2: https://bitbucket.org/jgraph/mxgraph2
        This is an official development repo of mxGraph. With npm issues.

If anyone wants to see what npm issues with these above repos(i.e. Repo-1 and Repo-2), then check these following issues:  
            - https://github.com/jgraph/mxgraph/issues/169
            - https://github.com/jgraph/mxgraph/issues/175

Repo-3: https://bitbucket.org/lgleim/mxgraph2
        Fork of Repo-2. With npm fixes.

Repo-4: https://github.com/ViksYelapale/mxgraph2
        Fork of Repo-2. Merged npm fixes from Repo-3 as well. Added changes(i.e. required for local installation of mxGraph) to this repo.

步骤:

  1. 克隆Repo-4。另外,添加官方repo(即Repo-2)的远程版本,以获取最新的mxGraph更新/发行版/修复程序。

  2. 将目录更改为mxgraph2并运行npm install

    $ cd mxgraph2
       $ npm install

  3. 现在转到您的角度项目存储库并安装mxGraph(即我们在本地构建的mxgraph2)。

    $ npm install /path/to/mxgraph2

    例如npm install /home/user/workspace/mxgraph2

    这将在package.json文件中添加如下所示的类似条目:

    "mxgraph": "file:../mxgraph2"

  4. 运行一次正常的npm安装。用于添加任何缺少/依赖的程序包。

    $ npm install

  5. 现在我们将安装mxgraph类型

    注意-打字稿的最低要求为2.4.0

    $ npm install lgleim/mxgraph-typings --save

  6. 现在您可以在应用程序中使用mxGraph。

    i。 component.ts

    import { mxgraph } from "mxgraph";
    
    declare var require: any;
    
    const mx = require('mxgraph')({
      mxImageBasePath: 'assets/mxgraph/images',
      mxBasePath: 'assets/mxgraph'
    });
    
    .
    .
    .
    
    ngOnInit() {
       // Note - All mxGraph methods accessible using mx.xyz
       // Eg. mx.mxGraph, mx.mxClient, mx.mxKeyHandler, mx.mxUtils and so on.
    
       // Create graph
    
       var container = document.getElementById('graphContainer');
       var graph = new mx.mxGraph(container);
    
       // You can try demo code given in official doc with above changes.
    }
    

    ii。 component.html

    <div id="graphContainer"></div>

  7. 就是这样!

希望这会有所帮助。

答案 2 :(得分:1)

这是我在Angular上实现mxGraph的使用方式。我希望这对其他人有帮助。

重要提示:这不适用于angular / cli --prod构建。您必须停用angular.json上的优化选项

"production": {
              "outputPath": "dist/PRO",
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              **"optimization": false,**
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
... and so on

首先从npm安装mxgraph和typins作为依赖项和dev-dependency

npm install mxgrapf --save
npm install @types/mxgraph --save-dev

这必须在项目的package.json中生成两个条目

"@types/mxgraph": "github:lgleim/mxgraph-typings",
"mxgraph": "4.0.4",

之后,我在同一文件中声明了所有需要扩展mxgraph的类,这节省了在使用mxgraph的所有类中声明const mx的开销。

扩展mxgraph类的文件是这样的:

import { mxgraph } from 'mxgraph'; // Typings only - no code!
declare var require: any;

/**
 *  init mxGraph whith a config object
 */
const mx: typeof mxgraph = require('mxgraph')({
    // mxgraph assets base path
    mxBasePath: 'assets/mxgraph',
    // mxgraph images
    mxImageBasePath: 'assets/mxgraph/images',
    // avoid mxgraph resources load
    mxLoadResources: false,
    mxForceIncludes: false

});

// Objects load in window object
// The original library load, loads object into the window object, this is necesray if you use
// the decode and encode models funcionality of mxgraph. Is necesary that you include all object you 
// use into your models. this is only my case.
window['mxGraphModel'] = mx.mxGraphModel;
window['mxGeometry'] = mx.mxGeometry;
window['MxGeometry'] = mx.mxGeometry;
window['MxPoint'] = mx.mxPoint;
window['mxPoint'] = mx.mxPoint;

/**
 * Into MXUTILITIES exports all the object created by mxgraph as staric properties as we need
 **/
export class MXUTILITIES {
    static mxEvent = mx.mxEvent;
    static mxUtils = mx.mxUtils;
    static mxConstants = mx.mxConstants;
    static mxStencilRegistry = mx.mxStencilRegistry;
    static mxPerimeter = mx.mxPerimeter;
    static mxEdgeStyle = mx.mxEdgeStyle;
    static mxEffects = mx.mxEffects;
    static mxClient = mx.mxClient;
    static mxCodecRegistry = mx.mxCodecRegistry;

}

/**
 * Exports for all classes we need extending mxgrah, you can extend, overwrite methods and so on
 * 
 */
export class MxGraphModel extends mx.mxGraphModel {}
export class MxOutline extends mx.mxOutline { }
export class MxKeyHandler extends mx.mxKeyHandler { }
export class MxCompactTreeLayout extends mx.mxCompactTreeLayout { }
export class MxLayoutManager extends mx.mxLayoutManager { }
export class MxDivResizer extends mx.mxDivResizer { }
export class MxCellOverlay extends mx.mxCellOverlay { }
export class MxImage extends mx.mxImage { }
export class MxEdgeHandler extends mx.mxEdgeHandler { }
export class MxPrintPreview extends mx.mxPrintPreview { }
export class MxWindow extends mx.mxWindow { }
export class MxGraphView extends mx.mxGraphView { }
export class MxGraphHandler extends mx.mxGraphHandler { }
export class MxGraphSelectionModel extends mx.mxGraphSelectionModel { }
export class MxToolbar extends mx.mxToolbar { }
export class MxEventObject extends mx.mxEventObject { }
export class MxCodec extends mx.mxCodec { }
export class MxObjectCodec extends mx.mxObjectCodec { }
export class MxFastOrganicLayout extends mx.mxFastOrganicLayout { }
export class MxGeometry extends mx.mxGeometry { }
export class MxHierarchicalLayout extends mx.mxHierarchicalLayout { }
export class MxStencil extends mx.mxStencil { }
export class MxRubberband extends mx.mxRubberband { }
export class MxCellRenderer extends mx.mxCellRenderer { }
export class MxPoint extends mx.mxPoint { }
export class MxConnector extends mx.mxConnector { }
export class MxLine extends mx.mxLine { }
export class MxArrowConnector extends mx.mxArrowConnector { }
export class MxCell extends mx.mxCell {}
export class MxGraph extends mx.mxGraph {}

要创建新图,我使用了一项服务,该服务存储生成的图并将所有选定的组件通知选定的单元格和创建的新图

import { Injectable, ElementRef } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
import { BehaviorSubject, Subject } from 'rxjs';
import { MxCell, MxGraph, MxEventObject, MXUTILITIES, MxGraphSelectionModel } from '../classes/mxgraph.class';


@Injectable({ providedIn: 'root' })
export class GraphsService { 

  private graphsSubject: BehaviorSubject<MxGraph[]> = new BehaviorSubject([]);
  private graphs$: Observable<MxGraph[]>;
  private graphs: MxGraph[] = [];
  
  private selectedCellsSubject: BehaviorSubject<MxCell[]> = new BehaviorSubject([]);
  private selectedCells$: Observable<MxCell[]>;
  private selectedCells: MxCell[];
  
  constructor() {
    this.graphs$ = this.graphsSubject.asObservable();
    this.stamp = Date.now();
  }
 
 /**
   * Generate a new graph into the received container
   *
   * @memberOf GraphsService
   */
  newGraph(graphContainer: ElementRef, name?: string): MxGraph {
    const newGraph: MxGraph = this.initNewGraph(graphContainer, name);
    this.graphs.push(newGraph);
    this.graphsSubject.next(this.graphs);
    return newGraph;
  }

  /**
   * Init new graph
   *
   * @memberOf GraphsService
   */
  private initNewGraph(graphContainer: ElementRef, name: string) {
    let newGraph: MxGraph;
    newGraph = new MxGraph(graphContainer.nativeElement);
    if (!name) name = 'Nuevo gráfico';
    newGraph.getModel().getRoot().setValue(name);
    newGraph.setConnectable(true);
    newGraph.setMultigraph(false);
    newGraph.selectionModel.addListener(MXUTILITIES.mxEvent.CHANGE, (mxGraphSelectionModel: MxGraphSelectionModel, evt: MxEventObject) => {
      this.emitSelectedCell(mxGraphSelectionModel.cells as MxCell[]);

    });

    return newGraph;
  }
  
  /**
   * Emits the selected cells from the graph
   * @memberOf GraphsService
   */
  private emitSelectedCell(cells: MxCell[]) {

    if (!cells) this.selectedCells = [];
    else this.selectedCells = cells;
    this.selectedCellsSubject.next(this.selectedCells);
  }

  
  }

答案 3 :(得分:1)

我也找不到任何可以解决此问题的资源。因此,我制作了自己的npm软件包,其他人也可以使用。您可以尝试为您的应用程序使用这些软件包之一。

ts-mxgraph打字稿包装的mxgraph库v4.03版本。
ts-mxgraph-factory打字稿包装器
ts-mxgraph-typings

我在项目中使用了以下方法。

步骤1:
在项目内创建mxgraph.overrides.ts文件

第2步
导入mxgraph原型方法。也可以扩展库本身的原始方法。

import '../../assets/deflate/base64.js'
import '../../assets/deflate/pako.min.js';

import { mxgraph, mxgraphFactory } from "ts-mxgraph";
const mx = mxgraphFactory({
    mxBasePath: 'mxgraph',
    mxLoadResources: false,
    mxLoadStylesheets: false,
});

declare const Base64: any;
declare const pako: any;

let mxActor: any = mx.mxActor;
let mxArrow: any = mx.mxArrow;
let mxArrowConnector: any = mx.mxArrowConnector;
let mxGraph: any = mx.mxGraph;
let mxClient: any = mx.mxClient;
let mxClipboard: any = mx.mxClipboard;
let mxCellMarker: any = mx.mxCellMarker;
let mxCodecRegistry: any = mx.mxCodecRegistry;
let mxDoubleEllipse: any = mx.mxDoubleEllipse;
let mxUtils: any = mx.mxUtils;
...
// extends mxgraph prototypes

mxGraph.prototype.updatePageBreaks = function(visible, width, height) {
    const useCssTranforms = this.useCssTransforms, scale = this.view.scale,
        translate = this.view.translate;

    if (useCssTranforms) {
        this.view.scale = 1;
        this.view.translate = new mxPoint(0, 0);
        this.useCssTransforms = false;
    }

    graphUpdatePageBreaks.apply(this, arguments);

    if (useCssTranforms) {
        this.view.scale = scale;
        this.view.translate = translate;
        this.useCssTransforms = true;
    }
}
// Adds panning for the grid with no page view and disabled scrollbars
const mxGraphPanGraph = mxGraph.prototype.panGraph;
mxGraph.prototype.panGraph = function(dx, dy) {
    mxGraphPanGraph.apply(this, arguments);

    if (this.shiftPreview1 != null) {
        let canvas = this.view.canvas;

        if (canvas.ownerSVGElement != null) {
            canvas = canvas.ownerSVGElement;
        }

        const phase = this.gridSize * this.view.scale * this.view.gridSteps;
        const position = -Math.round(phase - mxUtils.mod(this.view.translate.x * this.view.scale + dx, phase)) + 'px ' +
            -Math.round(phase - mxUtils.mod(this.view.translate.y * this.view.scale + dy, phase)) + 'px';
        canvas.style.backgroundPosition = position;
    }
}
...

export {
    mxClient,
    mxUtils,
    mxRubberband,
    mxEventObject,
    mxEdgeHandler,
    mxEvent,
    mxGraph,
    mxGraphModel,
    mxGeometry,
    mxConstants,
    ...
    }

// and then import these where you want to use them

import {
    mxClient,
    mxUtils,
    mxEvent,
    mxGraph,
    mxGraphModel,
    mxGeometry,
    mxConstants,
    mxCell,
    mxDictionary,
    mxCellEditor,
    mxStyleRegistry
} from './mxgraph.overrides';

import { IMAGE_PATH, STYLE_PATH, STENCIL_PATH, urlParams } from '../config';

declare var Base64: any;
declare var pako: any;

export class Graph extends mxGraph {
...
}

答案 4 :(得分:0)

有一个新的mxgraph TypeScripts类型定义包,其效果比其他任何一个都要好。

https://www.npmjs.com/package/mxgraph-type-definitions

这里是我按照以下步骤将其用于新的Angular 9项目的操作:

创建Angular 9应用程序:

ng new graphdemo

添加mxgraph:

npm install --save mxgraph

安装mxgraph TypeScript类型定义(这些定义比我在GitHub和NPM上找到的其他任何类型定义都更好):

npm install --save-dev mxgraph-type-definitions

按照那里的说明进行安装。我不确定Angular项目找到这些类型的最佳方法。但是对我来说,将以下行添加到我的应用程序的src / main.ts文件中是可行的:

/// <reference path="../node_modules/mxgraph-type-definitions/index.d.ts" />

添加内容为src / assets / js / mxgraph.conf.js的文件:

mxBasePath = 'mxgraph';

在angular.json中,我添加了:

"assets": [
  {"glob": "favicon.ico", "input": "/src", "output": "/" },
  {"glob": "**/*", "input": "src/assets/", "output": "/assets/" },
  {"glob": "**/*", "input": "./node_modules/mxgraph/javascript/src", "output": "/mxgraph"}
]

并且:

"scripts": [
  "src/assets/js/mxgraph.conf.js",
  "node_modules/mxgraph/javascript/mxClient.js"
]

在src / app / app.component.ts中:

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
  @ViewChild('graphContainer') graphContainer: ElementRef;

  ngAfterViewInit(): void {
    const graph = new mxGraph(this.graphContainer.nativeElement);

    try {
      const parent = graph.getDefaultParent();
      graph.getModel().beginUpdate();

      const vertex1: mxCell = graph.insertVertex(parent, '1', 'vertex 1', 0, 0, 70, 30);
      const vertex2: mxCell = graph.insertVertex(parent, '2', 'vertext 2', 0, 0, 70, 30);
      graph.insertEdge(parent, '3', '', vertex1, vertex2);

    } finally {
      graph.getModel().endUpdate();
      new mxHierarchicalLayout(graph).execute(graph.getDefaultParent());
    }
  }
}

最后,在src / app / app.component.html中:

<div #graphContainer id="graphContainer"></div>