GoJs - Angular 4: ОШИБКА TypeError: Невозможно прочитать свойство 'class' из null в Function.F.fromJson.F.fromJSON - PullRequest
0 голосов
/ 25 июня 2018

Я новичок в GoJS .поэтому я попытался создать пример проекта, взяв kanban sample , который находится на веб-сайте GoJs, используя Angular и Typescript.но я получил ошибку

AppComponent.html:1 ERROR TypeError: Cannot read property 'class' of null
at Function.F.fromJson.F.fromJSON 
Argument of type '() => void' is not assignable to parameter of type 'string | Constructor'.Type '() => void' is not assignable to type 'Constructor'.
Type '() => void' provides no match for the signature 'new (...args: any[]): Object'.

Сначала я написал скрипт в одном .ts файле, но я получил ошибку, поэтому функция

Unexpected token. A constructor, method, accessor, or property was expected.

Итак, я написал HTML-код на HTML-странице и разделил скрипт на два файла машинописного текста.

Я не могу понять, в чем заключается ошибка.

Может кто-нибудь помочь с этим?

error

import {
  Component,
  OnInit
} from '@angular/core';
import {
  HttpClient,
  HttpErrorResponse
} from '@angular/common/http';
import * as go from 'gojs';

@Component({
  selector: 'app-new-kanban',
  templateUrl: './new-kanban.component.html',
  styleUrls: ['./new-kanban.component.css']
})
export class NewKanbanComponent implements OnInit {
  // For the layout
  MINLENGTH = 200; // this controls the minimum length of any swimlane
  MINBREADTH = 100; // this controls the minimum breadth of any non-collapsed swimlane
  myDiagram: go.Diagram = new go.Diagram();
  cellSize: go.Size;
  wrappingColumn: number;
  wrappingWidth: number;
  spacing: go.Size;
  alignment: go.EnumValue;
  // some shared functions
  // this is called after nodes have been moved
  relayoutDiagram() {
    this.myDiagram.selection.each(function(n) {
      n.invalidateLayout();
    });
    this.myDiagram.layoutDiagram();
  }

  // compute the minimum size of the whole diagram export needed to hold all of the Lane Groups
  computeMinPoolSize() {
    let len = this.MINLENGTH;
    this.myDiagram.findTopLevelGroups().each(function(lane) {
      const holder = lane.placeholder;
      if (holder !== null) {
        const sz = holder.actualBounds;
        len = Math.max(len, sz.height);
      }
      const box = lane.selectionObject;
      // naturalBounds instead of actualBounds to disregard the shape's stroke width
      len = Math.max(len, box.naturalBounds.height);
    });
    return new go.Size(NaN, len);
  }

  // compute the minimum size for a particular Lane Group
  computeLaneSize(lane) {
    // assert(lane instanceof go.Group);
    const sz = this.computeMinLaneSize(lane);
    if (lane.isSubGraphExpanded) {
      const holder = lane.placeholder;
      if (holder !== null) {
        const hsz = holder.actualBounds;
        sz.width = Math.max(sz.width, hsz.width);
      }
    }
    // minimum breadth needs to be big enough to hold the header
    const hdr = lane.findObject('HEADER');
    if (hdr !== null) {
      sz.width = Math.max(sz.width, hdr.actualBounds.width);
    }
    return sz;
  }

  // determine the minimum size of a Lane Group, even if collapsed
  computeMinLaneSize(lane) {
    if (!lane.isSubGraphExpanded) {
      return new go.Size(1, this.MINLENGTH);
    }
    return new go.Size(this.MINBREADTH, this.MINLENGTH);
  }
  PoolLayout() {
    go.GridLayout.call(this);
    this.cellSize = new go.Size(1, 1);
    this.wrappingColumn = Infinity;
    this.wrappingWidth = Infinity;
    this.spacing = new go.Size(0, 0);
    this.alignment = go.GridLayout.Position;
  }
  constructor(private httpService: HttpClient) {
    go.Diagram.inherit(this.PoolLayout, go.GridLayout);
    /** @override */
    PoolLayout.prototype.doLayout = function(coll) {
      const diagram = this.diagram;
      if (diagram === null) {
        return;
      }
      diagram.startTransaction('PoolLayout');
      // make sure all of the Group Shapes are big enough
      const minsize = this.computeMinPoolSize();
      diagram.findTopLevelGroups().each(function(lane) {
        if (!(lane instanceof go.Group)) {
          return;
        }
        const shape = lane.selectionObject;
        if (shape !== null) { // change the desiredSize to be big enough in both directions
          const sz = this.computeLaneSize(lane);
          shape.width = (!isNaN(shape.width)) ? Math.max(shape.width, sz.width) : sz.width;
          shape.height = (isNaN(shape.height) ? minsize.height : Math.max(shape.height, minsize.height));
          const cell = lane.resizeCellSize;
          if (!isNaN(shape.width) && !isNaN(cell.width) && cell.width > 0) {
            shape.width = Math.ceil(shape.width / cell.width) * cell.width;
          }
          if (!isNaN(shape.height) && !isNaN(cell.height) && cell.height > 0) {
            shape.height = Math.ceil(shape.height / cell.height) * cell.height;
          }
        }
      });
      // now do all of the usual stuff, according to whatever properties have been set on this GridLayout
      go.GridLayout.prototype.doLayout.call(this, coll);
      diagram.commitTransaction('PoolLayout');
    };
  }
  ngOnInit() {
    const $ = go.GraphObject.make;
    this.myDiagram =
      $(go.Diagram, 'myDiagramDiv', {
        // start everything in the middle of the viewport
        contentAlignment: go.Spot.TopCenter,
        // use a simple layout to stack the top-level Groups next to each other
        layout: $(this.PoolLayout),
        // disallow nodes to be dragged to the diagram's background
        mouseDrop: function(e) {
          e.diagram.currentTool.doCancel();
        },
        // a clipboard copied node is pasted into the original node's group (i.e. lane).
        'commandHandler.copiesGroupKey': true,
        // automatically re-layout the swim lanes after dragging the selection
        'SelectionMoved': this.relayoutDiagram, // this DiagramEvent listener is
        'SelectionCopied': this.relayoutDiagram, // defined above
        'animationManager.isEnabled': false,
        'undoManager.isEnabled': true
      });
    // Customize the dragging tool:
    // When dragging a Node set its opacity to 0.7 and move it to the foreground layer
    this.myDiagram.toolManager.draggingTool.doActivate = function() {
      go.DraggingTool.prototype.doActivate.call(this);
      this.currentPart.opacity = 0.7;
      this.currentPart.layerName = 'Foreground';
    };
    this.myDiagram.toolManager.draggingTool.doDeactivate = function() {
      this.currentPart.opacity = 1;
      this.currentPart.layerName = '';
      go.DraggingTool.prototype.doDeactivate.call(this);
    };

    // There are only three note colors by default, blue, red, and yellow but you could add more here:
    const noteColors = ['#009CCC', '#CC293D', '#FFD700'];

    function getNoteColor(num) {
      return noteColors[Math.min(num, noteColors.length - 1)];
    }

    this.myDiagram.nodeTemplate =
      $(go.Node, 'Horizontal',
        new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
        $(go.Shape, 'Rectangle', {
            fill: '#009CCC',
            strokeWidth: 1,
            stroke: '#009CCC',
            width: 6,
            stretch: go.GraphObject.Vertical,
            alignment: go.Spot.Left,
            // if a user clicks the colored portion of a node, cycle through colors
            click: function(e, obj) {
              this.myDiagram.startTransaction('Update node color');
              let newColor = parseInt(obj.part.data.color, 10) + 1;
              if (newColor > noteColors.length - 1) {
                newColor = 0;
              }
              this.myDiagram.model.setDataProperty(obj.part.data, 'color', newColor);
              this.myDiagram.commitTransaction('Update node color');
            }
          },
          new go.Binding('fill', 'color', getNoteColor),
          new go.Binding('stroke', 'color', getNoteColor)
        ),
        $(go.Panel, 'Auto',
          $(go.Shape, 'Rectangle', {
            fill: 'white',
            stroke: '#CCCCCC'
          }),
          $(go.Panel, 'Table', {
              width: 130,
              minSize: new go.Size(NaN, 50)
            },
            $(go.TextBlock, {
                name: 'TEXT',
                margin: 6,
                font: '11px Lato, sans-serif',
                editable: true,
                stroke: '#000',
                maxSize: new go.Size(130, NaN),
                alignment: go.Spot.TopLeft
              },
              new go.Binding('text', 'text').makeTwoWay())
          )
        )
      );

    // unmovable node that acts as a button
    this.myDiagram.nodeTemplateMap.add('newbutton',
      $(go.Node, 'Horizontal', {
          selectable: false,
          click: function(e, node) {
            this.myDiagram.startTransaction('add node');
            const newdata = {
              group: 'Problems',
              loc: '0 50',
              text: 'New item ' + node.containingGroup.memberParts.count,
              color: 0
            };
            this.myDiagram.model.addNodeData(newdata);
            this.myDiagram.commitTransaction('add node');
            node = this.myDiagram.findNodeForData(newdata);
            this.myDiagram.select(node);
            this.myDiagram.commandHandler.editTextBlock();
          },
          background: 'white'
        },
        $(go.Panel, 'Auto',
          $(go.Shape, 'Rectangle', {
            strokeWidth: 0,
            stroke: null,
            fill: '#6FB583'
          }),
          $(go.Shape, 'PlusLine', {
            margin: 6,
            strokeWidth: 2,
            width: 12,
            height: 12,
            stroke: 'white',
            background: '#6FB583'
          })
        ),
        $(go.TextBlock, 'New item', {
          font: '10px Lato, sans-serif',
          margin: 6,
        })
      )
    );

    // While dragging, highlight the dragged-over group
    function highlightGroup(grp, show) {
      if (show) {
        const part = this.myDiagram.toolManager.draggingTool.currentPart;
        if (part.containingGroup !== grp) {
          grp.isHighlighted = true;
          return;
        }
      }
      grp.isHighlighted = false;
    }

    this.myDiagram.groupTemplate =
      $(go.Group, 'Vertical', {
          selectable: false,
          selectionObjectName: 'SHAPE', // even though its not selectable, this is used in the layout
          layerName: 'Background', // all lanes are always behind all nodes and links
          layout: $(go.GridLayout, // automatically lay out the lane's subgraph
            {
              wrappingColumn: 1,
              cellSize: new go.Size(1, 1),
              spacing: new go.Size(5, 5),
              alignment: go.GridLayout.Position,
              comparer: function(a, b) { // can re-order tasks within a lane
                const ay = a.location.y;
                const by = b.location.y;
                if (isNaN(ay) || isNaN(by)) {
                  return 0;
                }
                if (ay < by) {
                  return -1;
                }
                if (ay > by) {
                  return 1;
                }
                return 0;
              }
            }),
          click: function(e, grp) { // allow simple click on group to clear selection
            if (!e.shift && !e.control && !e.meta) {
              e.diagram.clearSelection();
            }
          },
          computesBoundsAfterDrag: true, // needed to prevent recomputing Group.placeholder bounds too soon
          handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links
          mouseDragEnter: function(e, grp, prev) {
            highlightGroup(grp, true);
          },
          mouseDragLeave: function(e, grp, next) {
            highlightGroup(grp, false);
          },
          mouseDrop: function(e, grp) { // dropping a copy of some Nodes and Links onto this Group adds them to this Group
            // don't allow drag-and-dropping a mix of regular Nodes and Groups
            if (e.diagram.selection.all(function(n) {
                return !(n instanceof go.Group);
              })) {
              const ok = grp.addMembers(grp.diagram.selection, true);
              if (!ok) {
                grp.diagram.currentTool.doCancel();
              }
            }
          },
          subGraphExpandedChanged: function(grp) {
            const shp = grp.selectionObject;
            if (grp.diagram.undoManager.isUndoingRedoing) {
              return;
            }
            if (grp.isSubGraphExpanded) {
              shp.width = grp._savedBreadth;
            } else {
              grp._savedBreadth = shp.width;
              shp.width = NaN;
            }
          }
        },
        new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
        new go.Binding('isSubGraphExpanded', 'expanded').makeTwoWay(),
        // the lane header consisting of a TextBlock and an expander button
        $(go.Panel, 'Horizontal', {
            name: 'HEADER',
            angle: 0, // maybe rotate the header to read sideways going up
            alignment: go.Spot.Left
          },
          $('SubGraphExpanderButton', {
            margin: 5
          }), // this remains always visible
          $(go.Panel, 'Horizontal', // this is hidden when the swimlane is collapsed
            new go.Binding('visible', 'isSubGraphExpanded').ofObject(),
            $(go.TextBlock, // the lane label
              {
                font: '15px Lato, sans-serif',
                editable: true,
                margin: new go.Margin(2, 0, 0, 0)
              },
              new go.Binding('text', 'text').makeTwoWay())
          )
        ), // end Horizontal Panel
        $(go.Panel, 'Auto', // the lane consisting of a background Shape and a Placeholder representing the subgraph
          $(go.Shape, 'Rectangle', // this is the resized object
            {
              name: 'SHAPE',
              fill: '#F1F1F1',
              stroke: null,
              strokeWidth: 4
            },
            new go.Binding('fill', 'isHighlighted', function(h) {
              return h ? '#D6D6D6' : '#F1F1F1';
            }).ofObject(),
            new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify)),
          $(go.Placeholder, {
            padding: 12,
            alignment: go.Spot.TopLeft
          }),
          $(go.TextBlock, // this TextBlock is only seen when the swimlane is collapsed
            {
              name: 'LABEL',
              font: '15px Lato, sans-serif',
              editable: true,
              angle: 90,
              alignment: go.Spot.TopLeft,
              margin: new go.Margin(4, 0, 0, 2)
            },
            new go.Binding('visible', 'isSubGraphExpanded', function(e) {
              return !e;
            }).ofObject(),
            new go.Binding('text', 'text').makeTwoWay())
        ) // end Auto Panel
      ); // end Group

    this.load();

    // Set up a Part as a legend, and place it directly on the diagram
    this.myDiagram.add(
      $(go.Part, 'Table', {
          position: new go.Point(300, 10),
          selectable: false
        },
        $(go.TextBlock, 'Key', {
          row: 0,
          font: '700 14px Droid Serif, sans-serif'
        }), // end row 0
        $(go.Panel, 'Horizontal', {
            row: 1,
            alignment: go.Spot.Left
          },
          $(go.Shape, 'Rectangle', {
            desiredSize: new go.Size(10, 10),
            fill: '#CC293D',
            margin: 5
          }),
          $(go.TextBlock, 'Halted', {
            font: '700 13px Droid Serif, sans-serif'
          })
        ), // end row 1
        $(go.Panel, 'Horizontal', {
            row: 2,
            alignment: go.Spot.Left
          },
          $(go.Shape, 'Rectangle', {
            desiredSize: new go.Size(10, 10),
            fill: '#FFD700',
            margin: 5
          }),
          $(go.TextBlock, 'In Progress', {
            font: '700 13px Droid Serif, sans-serif'
          })
        ), // end row 2
        $(go.Panel, 'Horizontal', {
            row: 3,
            alignment: go.Spot.Left
          },
          $(go.Shape, 'Rectangle', {
            desiredSize: new go.Size(10, 10),
            fill: '#009CCC',
            margin: 5
          }),
          $(go.TextBlock, 'Completed', {
            font: '700 13px Droid Serif, sans-serif'
          })
        ) // end row 3
      ));
  }
  // Show the diagram's model in JSON format
  save() {
    (document.getElementById('mySavedModel') as HTMLInputElement).value = this.myDiagram.model.toJson();
    this.myDiagram.isModified = false;
  }
  load() {
    const x = (document.getElementById('mySavedModel') as HTMLInputElement).value;
    console.log(x);
    this.httpService.get('kanban.json').subscribe(data => {
      this.myDiagram.model = go.Model;
    });
    this.myDiagram.model = go.Model.fromJson((document.getElementById('mySavedModel') as HTMLInputElement).value);
    this.myDiagram.delayInitialization(this.relayoutDiagram);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<p>
  new-kanban works!
</p>
<div id="sample">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:500px;"></div>
  <p>A Kanban board is a work and workflow visualization used to communicate the status and progress of work items. Click on the color of a note to cycle through colors.</p>
  <p>
    This design and implementation were adapted from the
    <a href="swimLanesVertical.html">Swim Lanes (vertical)</a> sample. Unlike that sample:
  </p>
  <ul>
    <li>there are no Links</li>
    <li>lanes cannot be nested into "pools"</li>
    <li>lanes cannot be resized</li>
    <li>the user cannot drop tasks into the diagram's background</li>
    <li>all tasks are ordered within a single column; the user can rearrange the order</li>
    <li>tasks can freely be moved into other lanes</li>
    <li>lanes are not movable or copyable or deletable</li>
  </ul>
  <p></p>
  <button id="SaveButton" (click)="save()">Save</button>
  <button (click)="load()">Load</button> Diagram Model saved in JSON format:
  <br>
  <textarea id="mySavedModel" style="width:100%;height:300px">{ "class": "go.GraphLinksModel", "nodeDataArray": [ {"key":"Problems", "text":"Problems", "isGroup":true, "loc":"0 23.52284749830794"
    }, {"key":"Reproduced", "text":"Reproduced", "isGroup":true, "color":"0", "loc":"109 23.52284749830794" }, {"key":"Identified",
    "text":"Identified", "isGroup":true, "color":"0", "loc":"235 23.52284749830794" }, {"key":"Fixing", "text":"Fixing",
    "isGroup":true, "color":"0", "loc":"343 23.52284749830794" }, {"key":"Reviewing", "text":"Reviewing", "isGroup":true,
    "color":"0", "loc":"451 23.52284749830794"}, {"key":"Testing", "text":"Testing", "isGroup":true, "color":"0", "loc":"562
    23.52284749830794" }, {"key":"Customer", "text":"Customer", "isGroup":true, "color":"0", "loc":"671 23.52284749830794"
    }, {"key":-1, "group":"Problems", "category":"newbutton", "loc":"12 35.52284749830794" }, {"key":1, "text":"text for
    oneA", "group":"Problems", "color":"0", "loc":"12 35.52284749830794"}, {"key":2, "text":"text for oneB", "group":"Problems",
    "color":"1", "loc":"12 65.52284749830794"}, {"key":3, "text":"text for oneC", "group":"Problems", "color":"0", "loc":"12
    95.52284749830794"}, {"key":4, "text":"text for oneD", "group":"Problems", "color":"1", "loc":"12 125.52284749830794"},
    {"key":5, "text":"text for twoA", "group":"Reproduced", "color":"1", "loc":"121 35.52284749830794"}, {"key":6, "text":"text
    for twoB", "group":"Reproduced", "color":"1", "loc":"121 65.52284749830794"}, {"key":7, "text":"text for twoC", "group":"Identified",
    "color":"0", "loc":"247 35.52284749830794"}, {"key":8, "text":"text for twoD", "group":"Fixing", "color":"0", "loc":"355
    35.52284749830794"}, {"key":9, "text":"text for twoE", "group":"Reviewing", "color":"0", "loc":"463 35.52284749830794"},
    {"key":10, "text":"text for twoF", "group":"Reviewing", "color":"1", "loc":"463 65.52284749830794"}, {"key":11, "text":"text
    for twoG", "group":"Testing", "color":"0", "loc":"574 35.52284749830794"}, {"key":12, "text":"text for fourA", "group":"Customer",
    "color":"1", "loc":"683 35.52284749830794"}, {"key":13, "text":"text for fourB", "group":"Customer", "color":"1", "loc":"683
    65.52284749830794"}, {"key":14, "text":"text for fourC", "group":"Customer", "color":"1", "loc":"683 95.52284749830794"},
    {"key":15, "text":"text for fourD", "group":"Customer", "color":"0", "loc":"683 125.52284749830794"}, {"key":16, "text":"text
    for fiveA", "group":"Customer", "color":"0", "loc":"683 155.52284749830795"} ], "linkDataArray": []}
  </textarea>
</div>

1 Ответ

0 голосов
/ 20 июля 2018

Это неверно и вызывает ошибку:

this.myDiagram.model = go.Model;

Вы должны установить Diagram.model на экземпляр Модель , который вы создаете с помощьюданные, которые вы получаете, не для модель класс.

...