8.custom-links

JointJS comes with several built-in link shapes; we have already encountered joint.shapes.standard.Link in the basic links tutorial.
JointJS有几个内置的链接形状;我们在“基本链接”教程中已经遇到joint.shapes.standard.link。

However, builtin link definitions are not as plentiful as element definitions. It is thus very possible that you will find the need to define your own custom link type. Creating custom links is very similar to creating custom elements, with a few differences. The Link class is discussed in JointJS documentation, as well.
但是,内置链接定义不如元素定义丰富。因此,您很可能会发现需要定义自己的自定义链接类型。创建自定义链接与创建自定义元素非常相似,但有一些区别。链接类也在jointjs文档中讨论。
plentiful
英 [ˈplentɪfl] 美 [ˈplentɪfl]
adj.大量的;众多的;充足的;丰富的

A new Link subtype is registered by calling the define() function:
通过调用define()函数注册新的链接子类型:

  • Link.define(type [, defaultInstanceProperties, prototypeProperties, staticProperties]) - define a new subtype of this Link class. 定义此链接类的新子类型。

If you want to create a Link subtype from scratch, you should inherit from the default joint.dia.Link class by calling joint.dia.Link.define(). You can also inherit from any predefined link (e.g. joint.shapes.standard.Link.define()) and even any custom link subtype you have previously defined.
如果要从头创建链接子类型,应通过调用joint.dia.Link.define()从默认joint.dia.link类继承。您还可以从任何预定义链接(例如joint.shapes.standard.Link.define())继承,甚至可以从以前定义的任何自定义链接子类型继承。

Here is how the parameters of the define() function map to familiar building blocks of links:
下面是define()函数的参数如何映射到熟悉的链接构建块:

  • type - the name of the subtype class. 子类型类的名称。
  • defaultInstanceProperties - object that contains properties to be assigned to every constructed instance of the subtype. Used for specifying default attributes. 包含要分配给子类型的每个构造实例的属性的对象。用于指定默认属性。
  • prototypeProperties - object that contains properties to be assigned on the subtype prototype. Intended for properties intrinsic to the subtype, not usually modified. Used for specifying shape markup. 包含要在子类型原型上分配的属性的对象。用于子类型固有的属性,通常不修改。用于指定形状标记。
  • staticProperties - object that contains properties to be assigned on the subtype constructor. Not very common, used mostly for alternative constructor functions.
    包含要在子类型构造函数上分配的属性的对象。不太常见,主要用于可选的构造函数函数。

Let us use the familiar joint.shapes.standard.Link shape definition as an example:
让我们以熟悉的joint.shapes.standard.link形状定义为例:

joint.dia.Link.define('standard.Link', {
    attrs: {
        line: {
            connection: true,
            stroke: '#333333',
            strokeWidth: 2,
            strokeLinejoin: 'round',
            targetMarker: {
                'type': 'path',
                'd': 'M 10 -5 0 0 10 5 z'
            }
        },
        wrapper: {
            connection: true,
            strokeWidth: 10,
            strokeLinejoin: 'round'
        }
    }
}, {
    markup: [{
        tagName: 'path',
        selector: 'wrapper',
        attributes: {
            'fill': 'none',
            'cursor': 'pointer',
            'stroke': 'transparent'
        }
    }, {
        tagName: 'path',
        selector: 'line',
        attributes: {
            'fill': 'none',
            'pointer-events': 'none'
        }
    }]
});
Name

The first argument of the define() function is a unique identifier under which you want to be able to find the new type. The first part of the name, joint.shapes, is implied. Thus, we can see that the name of a type accessed as joint.shapes.standard.Link has to be 'standard.Link'.
define()函数的第一个参数是一个唯一的标识符,您希望在该标识符下能够找到新的类型。名称的第一部分joint.shapes是隐含的。因此,我们可以看到作为joint.shapes.standard.link访问的类型的名称必须是“standard.link”。

Markup

Markup is usually provided inside the third argument of the define() function (prototype properties) for improved performance. (This is because markup is something that all instances of the link type are expected to have in common, so inheriting from subtype prototype is more efficient. Nevertheless, it is still possible to provide custom markup to individual instances of your class by providing individual markup later.)
为了提高性能,通常在define()函数(原型属性)的第三个参数中提供标记。(这是因为标记是期望链接类型的所有实例都具有的共同点,因此从子类型原型继承更有效。不过,通过稍后提供单个标记,仍然可以为类的各个实例提供自定义标记。)

The markup property is specified as a JSON array. Each member of the array is taken to define one subelement of the new shape. Subelements are defined with objects containing a tagName (a string with the SVG tag name of the subelement) and a selector (a string identifier for this subelement in the shape). Although JointJS can also understand SVG markup in string form, that approach is noticeably slower due to the need for parsing and lack of capacity for custom selectors.

标记属性被指定为JSON数组。数组的每个成员都被用来定义新形状的一个子元素。子元素由包含标记名(子元素的svg标记名字符串)和选择器(形状中此子元素的字符串标识符)的对象定义。尽管JointJS也可以理解字符串形式的SVG标记,但是由于需要解析和缺少自定义选择器的容量,这种方法明显较慢。

A joint.shapes.standard.Link is composed of two subelements - an SVGPathElement named line and an SVGPathElement named wrapper. The line is the subelement that is supposed to be styled, while wrapper is a transparent helper subelement underneath the line that is designed to be interacted with.

joint.shapes.standard.link由两个子元素组成—一个名为line的SVGPathElement 和一个名为wrapper的SVGPathElement 。line 是应该设置样式的子元素,而wrapper 是设计用于交互的line 下面的透明辅助子元素。

{
    markup: [{
        tagName: 'path',
        selector: 'wrapper',
        attributes: {
            'fill': 'none',
            'cursor': 'pointer',
            'stroke': 'transparent'
        }
    }, {
        tagName: 'path',
        selector: 'line',
        attributes: {
            'fill': 'none',
            'pointer-events': 'none'
        }
    }]
}

As you can see, attributes can also be defined inside markup. These are intended for attributes that all instances of a link type are expected to have in common; for such attributes, it is more efficient to inherit these attributes from the subtype prototype instead of each instance having their own copy because it avoids unnecessary iterations in the cell attributes update loop. (Nevertheless, again, it is possible to overwrite these prototype attributes by individual instance attributes if absolutely necessary.)
如您所见,属性也可以在标记内定义。这些用于链接类型的所有实例都希望具有共同的属性;对于此类属性,从子类型原型继承这些属性更有效,而不是每个实例都有自己的副本,因为这样可以避免单元属性更新循环中不必要的迭代。(不过,如果绝对必要,也可以用单个实例属性覆盖这些原型属性。)
intend
英 [ɪnˈtend] 美 [ɪnˈtend]
v.打算;计划;想要;意指

In our example, markup.attributes are used to reflect the intended use of the two subelements of the link, which is not expected to change - wrapper has a transparent stroke since it is not expected to be styled, while line has ‘pointer-events’ deactivated since it is not expected to be interacted with. Both subelement paths also remove the default SVGPathElement ‘fill’ which is not usually terribly useful within links.
在我们的示例中,markup.attributes用于反映link的两个子元素的预期用途,这是不希望更改的-wrapper 具有透明的笔画,因为它不希望被设置为样式,而line具有“pointer-events”,因为它不希望与之交互。两个子元素路径都会删除默认的SVGPathElement “fill”,这在links中通常不太有用。
=>markup.attributes里面的属性,是不希望被修改的!

An important caveat is that markup.attributes can only store native SVG attributes, not JointJS attrs. This means that JointJS special attributes are not recognized (since markup.attributes are supposed not to change, they would not be able to reflect possible changes in referenced subelements or in the size/position of model bbox). Additionally, this means that there is no JointJS kebab-case translation of attribute names; thus, using quotes around all attribute names is encouraged in this context, to communicate these restrictions to programmers (i.e. 'fill', not fill; 'pointer-events', not pointerEvents).
caveat
英 [ˈkæviæt] 美 [ˈkæviæt]
n.警告;告诫
=>markup.attributes里面的属性,不能使用驼峰式的,使用kebab-case类型,eg:'fill''pointer-events'

一个重要的警告是markup.attributes只能存储本机SVG属性,而不能存储jointJS属性。这意味着JointJS 的特殊属性无法识别(因为markup.attributes不应该更改,所以它们无法反映引用子元素或模型bbox的大小/位置中可能发生的更改)。此外,这意味着属性名不存在jointjs kebab大小写转换;因此,在此上下文中,鼓励在所有属性名周围使用引号,将这些限制传达给程序员(即'fill',而不是fill'pointer-events',而不是pointerEvents)。

Default Attributes

Default attributes are usually provided inside the second argument of the define() function (default instance properties). (This is because all instances of the link type are expected to have their own individual attributes, so inheriting from the prototype is likely to cause unnecessary overhead.)
默认属性通常在define()函数的第二个参数(默认实例属性)中提供。(这是因为链接类型的所有实例都有自己的单独属性,因此从原型继承可能会导致不必要的开销。)

In the attrs object, keys correspond to subelement selectors, as defined in the markup. For each subelement, an object with attribute name-value pairs is then expected. Each of these attributes can be a native SVG attribute or a JointJS special attribute.
在attrs对象中,键对应于子元素选择器,如标记中所定义的。对于每个子元素,则需要一个具有属性名-值对(键值对)的对象。这些属性中的每一个都可以是本机SVG属性或JointJS特殊属性。

In joint.shapes.standard.Link, we can see that the subelement referenced by line (i.e. the stylable SVGPathElement component of the link) has a default dark-gray stroke of width 2, and a default target marker that looks like a small arrow. (Since the default target marker has no fill or stroke set, the colors are inherited from the line.stroke attribute by default.) The wrapper subelement (the interactive SVGPathElement component of the link) has a wider transparent stroke to make the link easier to click for users. Finally, notice that both subelements have the connection special attribute set to true. This means that they both automatically follow the connection path of the link instance as calculated by the link geometry functions:
在joint.shapes.standard.link中,我们可以看到line 引用的子元素(即link的可设置样式的SVGPathElement 组件)具有一个默认的2px深灰色stroke,以及一个看起来像小箭头的默认目标标记。(由于默认目标标记没有填充或笔划集,因此默认情况下颜色是从line.stroke属性继承的。)wrapper 子元素(link的交互式SVGPathElement 组件)具有更宽的透明笔划,使用户更容易单击链接。最后,注意这两个子元素的connection 特殊属性都设置为true。这意味着它们都会自动遵循由链接几何体函数计算的链接实例的连接路径:

{
    attrs: {
        line: {
            connection: true,
            stroke: '#333333',
            strokeWidth: 2,
            strokeLinejoin: 'round',
            targetMarker: {
                'type': 'path',
                'd': 'M 10 -5 0 0 10 5 z'
            }
        },
        wrapper: {
            connection: true,
            strokeWidth: 10,
            strokeLinejoin: 'round'
        }
    }
}
Default Label

The second argument of the define() function (default instance properties) is also where defaultLabel for custom Link subtypes may be specified. This allows you to provide custom default markup and attrs for labels that are created on an instance of your custom Link type. The joint.shapes.standard.Link does not define its own custom default label, so the builtin default markup and attributes are used unless they are overridden by individual label markup and attrs.
define()函数(默认实例属性)的第二个参数也是可以指定自定义链接子类型的defaultLabel的地方。这允许您为在自定义链接类型实例上创建的标签提供自定义默认标记和属性。joint.shapes.standard.link不定义自己的自定义默认标签,因此使用内置默认标记和属性,除非它们被单个标签标记和属性覆盖。

The defaultLabel accepts three properties:默认标签接受三个属性:

  • defaultLabel.markup - sets the default markup of labels created on this Link subtype. Expected in the JSON markup format.
    (An SVG-parsable string is also accepted, but it is slower.) See default.
  • defaultLabel.attrs - sets the default attributes of label subelements on this Link subtype. Uses selectors defined in markup. See default.
  • defaultLabel.position - sets the default position along the line at which labels will be added for instances of this Link subtype. Default is 0.5 (midpoint of the connection path).
  1. 设置在此链接子类型上创建的标签的默认标记。JSON标记格式中应为。

(也接受SVG可分析字符串,但速度较慢。)请参见默认值。

  1. 设置此链接子类型上标签子元素的默认属性。使用标记中定义的选择器。参见默认值。
  2. 设置将为此链接子类型的实例添加标签的行的默认位置。默认值为0.5(连接路径的中点)。

默认值:http://resources.jointjs.com/docs/jointjs/v2.2/joint.html#dia.Link.intro.builtinDefaultAttributes

Static Properties

Static properties are not used by joint.shapes.standard.Link, but let us discuss them a little bit to gain a complete overview of custom links.
joint.shapes.standard.link不使用静态属性,但让我们稍微讨论一下,以获得自定义链接的完整概述。

Similarly to our custom element example, imagine we wanted to define our own subtype of joint.shapes.standard.Link (which we name ‘examples.CustomLink’), with the added benefit of a constructor function that chose a random style for the link’s line - maybe because we need to add a lot of diverse links quickly. We could do this with a static function createRandom; then, we would have two ways to obtain an instance of CustomLink:

与我们的自定义元素示例类似,假设我们想要定义自己的joint.shapes.standard.link子类型(我们将其命名为“example s.customlink”),并为链接的行选择一个随机样式的构造函数函数带来了额外的好处-可能是因为我们需要快速添加大量不同的链接。我们可以用一个静态函数createrandom来实现这一点;然后,我们将有两种方法来获取customlink的实例:

var customLink = new joint.shapes.examples.CustomLink();

var customLink = joint.shapes.examples.CustomLink.createRandom();

Both of these functions are demonstrated in our example.这两个函数都在我们的示例中演示。

Example

Let us apply everything we learned so far and create a new joint.shapes.examples.CustomLink class based on joint.shapes.standard.Link. Keep in mind that the provided instance properties are mixined with the parent definition, but prototype and static properties are not. This means that it is enough for us to record only the attributes that changed in the definition of the custom element subtype (however, if we wanted to change the markup, we would have to do so explicitly).
让我们应用到目前为止所学的一切,并基于joint.shapes.standard.link创建一个新的joint.shapes.examples.customlink类。请记住,提供的实例属性与父定义混合在一起,但原型属性和静态属性不是。这意味着我们只记录在自定义元素子类型定义中更改的属性就足够了(但是,如果我们想要更改标记,就必须显式进行更改)。

The following example shows the default look of joint.shapes.standard.Link (i.e. with no instance attributes set) alongside the default look of our custom link and the randomized results of the createRandom() constructor function. Every link has a default label added as well. Try refreshing the page to see createRandom() in action.
下面的示例显示了joint.shapes.standard.link的默认外观(即没有设置实例属性)以及自定义链接的默认外观和createRandom()构造函数函数的随机结果。每个链接都添加了一个默认标签。尝试刷新页面以查看操作中的CreateRandom()。

    joint.shapes.standard.Link.define('examples.CustomLink', {
        attrs: {
            line: {
                stroke: 'cornflowerblue',
                strokeWidth: 5,
                targetMarker: {
                    'type': 'rect',
                    'width': 10,
                    'height': 20,
                    'y': -10,
                    'stroke': 'none'
                }
            }
        },
        defaultLabel: {
            markup: [
                {
                    tagName: 'rect',
                    selector: 'body'
                }, {
                    tagName: 'text',
                    selector: 'label'
                }
            ],
            attrs: {
                label: {
                    fill: 'red', // default text color
                    fontSize: 12,
                    textAnchor: 'middle',
                    yAlignment: 'middle',
                    pointerEvents: 'none'
                },
                body: {
                    ref: 'label',
                    fill: 'white',
                    stroke: 'cornflowerblue',
                    strokeWidth: 2,
                    refWidth: '120%',
                    refHeight: '120%',
                    refX: '-10%',
                    refY: '-10%'
                }
            },
            position: {
                distance: 100, // default absolute position
                args: {
                    absoluteDistance: true
                }
            }
        }
    }, {
        // inherit joint.shapes.standard.Link.markup
    }, {
        createRandom: function() {

            var link = new this();

            var stroke = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6);
            var strokeWidth = Math.floor(Math.random() * 10) + 1;
            var strokeDasharray = (Math.floor(Math.random() * 5) + 1) + ' ' + (Math.floor(Math.random() * 5) + 1);

            link.attr({
                line: {
                    stroke: stroke,
                    strokeWidth: strokeWidth,
                    strokeDasharray: strokeDasharray
                }
            });

            link.prop('defaultLabel/attrs/body/stroke', stroke);

            return link;
        }
    });

    var link = new joint.shapes.standard.Link();
    link.source(new g.Point(100, 50));
    link.target(new g.Point(500, 50));
    link.appendLabel({
        attrs: {
            text: {
                text: 'Hello, World!'
            }
        }
    });
    link.addTo(graph);


    var link2 = new joint.shapes.examples.CustomLink();
    link2.source(new g.Point(100, 150));
    link2.target(new g.Point(500, 150));
    link2.appendLabel({
        attrs: {
            label: {
                text: 'Hello, World!'
            }
        }
    });
    link2.addTo(graph);



    var link3 = joint.shapes.examples.CustomLink.createRandom();
    link3.source(new g.Point(100, 250));
    link3.target(new g.Point(500, 250));
    link3.appendLabel({
        attrs: {
            label: {
                text: 'Hello, World!'
            }
        }
    });
    link3.addTo(graph);

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值