creating my own shape definition in jointjs doesn't work in angular7

Viewed 442

I am using angular 7 and joint.js to create my own shape definition. For example,

joint.shapes.devs.Model.define("devs.Type",
  {
    size: {
      width: 300,
      height: "auto"
    }
 });

joint.shapes.standard.Rectangle.define('examples.CustomRectangle', {
    attrs: {
        body: {
            rx: 10, // add a corner radius
            ry: 10,
            strokeWidth: 1,
            fill: 'cornflowerblue'
        },
        label: {
            textAnchor: 'left', // align text to left
            refX: 10, // offset text from right edge of model bbox
            fill: 'white',
            fontSize: 18
        }
    }
});






var rect2 = new joint.shapes.examples.CustomRectangle();
var a1 = new joint.shapes.devs.Type(node);

Compiling the code gives me two errors

error TS2339: Property 'Type' does not exist on type 'typeof devs' error TS2341:Property 'examples' does not exist on type 'typeof shapes'.

How would I solve this problem?


Moreover, the customer Link defines a transitionColor method, but it can't be called in paper.on("link:mouseover",...., the error is

Property 'transitionColor' does not exist on type 'Link'.

joint.dia.Link.define(
      "devs.Link",
      {
        attrs: {
          line: {
            connection: true
          },
          wrapper: {
            connection: true,
            strokeWidth: 2,
            strokeLinejoin: "round"
          }
        }
      },
      {
        markup: [
          {
            tagName: "path",
            selector: "wrapper",
            attributes: {
              fill: "none",
              cursor: "pointer",
              stroke: "transparent"
            }
          },
          {
            tagName: "path",
            selector: "line",
            attributes: {
              fill: "none",
              "pointer-events": "none"
            }
          }
        ],
        transitionAsync: function (...args) {
          return new Promise(resolve => {
            this.transition(...args);
            this.on("transition:end", () => {
              resolve();
            });
          });
        },
        transitionColor: function (color, { delay = 0, duration = 100 }) {
          return this.prop("attrs/line/stroke", color);
        },
        transitionOpacity: function (opacity, { delay = 0, duration = 100 }) {
          return this.prop("attrs/line/opacity", opacity);
        }
      }
    );


paper.on("link:mouseover", (linkView: any) => {
      const links = this.graph.getLinks();
      links.map(link => {
        if (link === linkView.model) {
          return;
        }
        link.transitionColor(theme.colors.line.inactive, {duration:500});
        link.toBack()
      });
});
1 Answers

Your problem is with TypeScript, not with Angular, and probably with the typings available for the library.

Your error message reads 'Type' does not exist on type 'typeof devs'. This means that your variable devs is not typed, so TypeScript infers the type dynamically, from the variable definition:

// devs is not declared this way, but this is just to make the point
const devs = {
  prop1: string;
  prop2: number;
};

// you can add extra properties with the JavaScript square brackets access:
devs['Type'] = function() { ... }

devs['Type']() // <- this call works

devs.Type() // <-- compile time exception: Type is not present in the type.

To exit from this conundrum you can:

  1. Understand if there is a problem with the typings available for the library, and load an appropriate typings file (a .d.ts file coming from some library). This is by far the preferred option if someone else has bothered defining the type signatures, because your code is checked at compile time. If you don't have access to typings file, however, compiling them by end is impractical.
  2. Opt out from the TypeScript type system and just use any. If you know the library, and you are comfortable in using it in plain 'ol JavaScript, you can just declare that the objects you are using are NOT typed:
// this out of any class body declares that somewhere in window, a joint object exists, and we don't know anything about it
declare const joint: any;

// or, when calling a subsection of joint with bad or incomplete typings:
const a1 = new (joint.shapes.devs as any).Type(node);
// same meaning, different syntax:
const a2 = new (<any>joint.shapes.devs).Type(node);

// you can just get an untyped reference to devs and use it:
const untypedDevs: any = joint.shapes.devs;
const a3 = new untypedDevs.Type(node);

In general, you should try to learn at least a bit of TypeScript, because that is the language you are using, now.

Hope it helps!

Related