如何将 mxGraph 与 Angular 4 集成?

How to integrate mxGraph with Angular 4?

我正在研究 Angular 4,我想将 mxGraph 集成到我的项目中。 我用谷歌搜索了它,但没有得到完整的工作示例。

我试过以下方法,但它也不适合我。

我遵循的步骤:

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

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

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

    Github mxgraph 类型的回购 - 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

    然后我得到 issue/error 比如:
    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

    这次我也是一样issue/error:
    Module not found: Error: Can't resolve 'mxgraph' in 'path to my file where I have imported and used mxgraph'

有人知道我在这里遗漏了什么吗?或者为什么它不起作用?

如果有人知道 other/better 将 mxGraph 与 Angular 4 集成的方法,请告诉我。

提前致谢!!

我遇到了完全相同的问题。根据 '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 下载打字。将文件解压缩到 angular 项目

的 '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"

有两个脚本和资产数组。一次在 "build" 中,一次在 "test" 中。两者都加。

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

示例代码:

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());
    }
  }

}

请注意,我已使用 declare 语句来声明 mxPerimetermxConstants。原因是类型定义不完整。因此我不得不自己声明一些 class 名称。这只是一个避免编译器错误的小技巧。通过使用 declare 语句,我实际上是在告诉编译器允许这个 class。然而,它对各种文本编辑器使用的智能感知没有帮助。

如果有人还在 Angular 4/5/6 中为 mxGraph 集成而苦苦挣扎。那么这里是完整的解决方案:

关于不同 mxGraph Repos 的一些细节:

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 updates/release/fixes.

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

    $ cd mxgraph2
    $ npm install

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

    $ npm install /path/to/mxgraph2

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

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

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

  4. 运行 正常 npm install 一次。用于添加任何 missing/dependency 包。

    $ npm install

  5. 现在我们将安装 mxgraph typings

    注意 - 打字稿的最低要求版本是 2.4.0

    $ npm install lgleim/mxgraph-typings --save

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

    我。 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.
    }
    

    二。 component.html

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

  7. 就是这样!!

希望对您有所帮助。

这就是我在 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 和 typin 作为依赖和开发依赖

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

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

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

之后我在同一个文件中声明所有我需要的 classes 扩展 mxgraph 这节省了在所有使用 mxgraph 的 class 中声明 const mx 的成本。

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

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);
  }

  
  }

我也找不到任何可以解决这个问题的资源。所以我制作了自己的 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 {
...
}

Draw.io 图形编辑器库

npm install --save @zklogic/draw.io