简体   繁体   English

如何为自定义元素扩展 ElementView 以便它实际显示我想要的内容并无错误地接受标记?

[英]How do I extend ElementView for a custom element so that it actually displays what I want and accepts the markup without error?

I have a jsFiddle of JointJS code that gives me what I want: https://jsfiddle.net/RaymondMH/s46uyq8v/156/我有一个 JointJS 代码的 jsFiddle,它给了我想要的东西: https://jsfiddle.net/RaymondMH/s46uyq8v/156/

However, when I try to make use of this code in my actual application, none of the functions defined in the ElementView.extend() call ever get called, and the Element does not get created like I want it to.但是,当我尝试在实际应用程序中使用此代码时, ElementView.extend()调用中定义的任何函数都不会被调用,并且不会像我想要的那样创建元素。

This is how I put it in my code:这就是我把它放在我的代码中的方式:

import { Injectable } from '@angular/core';
import * as joint from '@clientio/rappid';
import * as _ from 'lodash';
import * as V from 'jquery';

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

    private SystemElement: any;

    constructor() {
    }

    public GetNodeElement(): { node: joint.dia.Element, embedId: number } {
        let element: joint.dia.Element;
        element = new this.SystemElement();
        element
            .prop('numberOfComponents', 4)
            .position(150, 150);
        return { node: element, embedId: null };
    }

    public InitializeDefinitions() {
        let componentOutlineRect = {
            x: 0, y: 0, width: 215, height: 24,
            fill: '#fafafa', stroke: '#000000', 'stroke-width': '0.1'
        }

        let componentText = {
            x: 0, y: 0,
            fill: 'black',
            'font-size': 13, 'font-family': 'Arial', 'font-weight': 'normal'
        }

        let componentStatusText = {
            x: 14, y: 18,
            'font-size': 13, 'font-family': 'Arial', 'font-weight': '600',
            fill: 'green'
        }

        let componentIconRect = {
            x: 34, y: 5, width: 16, height: 16,
            fill: '#565656'
        }

        this.SystemElement = joint.dia.Element.extend({
            defaults: joint.util.defaultsDeep({
                type: 'custom.Element',
                outlineColor: 'black',
                numberOfComponents: 1,
                size: {
                    width: 215,
                    height: 24
                },
                attrs: {
                    body: {
                        ...componentOutlineRect,
                        fill: '#bebebe'
                    },
                    bodytitle: {
                        ...componentText
                    },
                    components: {
                        ...componentOutlineRect,
                        y: 24,
                    }
                }
            }),
            markup: [
                { tagName: 'rect', selector: 'body' },
                { tagName: 'text', selector: 'bodytitle' },
                { tagName: 'rect', selector: 'components' },
                { tagName: 'text', selector: 'componentStatus' },
                { tagName: 'rect', selector: 'componentIcons' },
                { tagName: 'text', selector: 'text' }
            ]
        });
        this.SystemElement.ElementView = joint.dia.ElementView.extend(
            {
                events: {
                    'dblclick': 'onDblClick',
                    'click .components': 'onComponentClick'
                },

                init: function () {
                    console.log('************* init() function called!');
                    var model = this.model;
                    this.listenTo(model, [
                        'change:fillColor',
                        'change:outlineColor',
                    ].join(' '), this.update);
                    this.listenTo(model, 'change:numberOfComponents', this.render);
                },

                render: function () {
                    console.log('**************** render function called!');
                    var markup = this.constructor.markup;
                    var body = this.vBody = markup.body.clone();
                    var bodyTitle = this.vBodyTitle = markup.bodytitle.clone().text('A - Static Structural');
                    var components = this.vComponents = [];
                    var componentStatus = this.vComponentStatus = [];
                    var componentIcons = this.vComponentIcons = [];
                    var componentLabels = this.vComponentLabels = [];
                    for (var i = 0, n = this.model.prop('numberOfComponents'); i < n; i++) {
                        components.push(markup.components.clone());
                        componentStatus.push(markup.componentStatus.clone().text('✓'));
                        componentIcons.push(markup.componentIcons.clone());
                        componentLabels.push(markup.text.clone().text('Component ' + (i + 1)));
                    }
                    this.vel.empty().append(
                        _.flatten([
                            body,
                            components
                        ])
                    );
                    this.translate();
                    this.update();
                },

                update: function () {
                    this.updateBody();
                    this.updateComponents();
                },

                updateBody: function () {
                    var model = this.model;
                    var bodyAttributes = {
                        ...componentOutlineRect,
                        fill: '#aaaaaa',
                    };
                    this.vBody.attr(bodyAttributes);

                    var bodyTitle = this.vBodyTitle;
                    bodyTitle.attr({
                        ...componentText,
                        'font-weight': '600',
                        transform: 'translate(14,16)'
                    });
                    this.vel.append(bodyTitle);
                },

                updateComponents: function () {
                    console.log('************** updateComponents called!');
                    var model = this.model;
                    var numberOfComponents = model.prop('numberOfComponents');
                    var vComponents = this.vComponents;
                    for (var i = 0; i < numberOfComponents; i++) {
                        vComponents[i].attr({
                            ...componentOutlineRect,
                            y: 24 * (i + 1),
                            'data-index': i
                        });
                    }

                    var vComponentStatus = this.vComponentStatus;
                    for (var i = 0; i < numberOfComponents; i++) {
                        var vStatus = vComponentStatus[i];
                        var tx = 14;
                        var ty = 24 * (i + 1);
                        vStatus.attr({
                            ...componentStatusText,
                            transform: 'translate(' + tx + ',' + ty + ')'
                        });
                        this.vel.append(vStatus);
                    }

                    var vComponentIcons = this.vComponentIcons;
                    for (var i = 0; i < numberOfComponents; i++) {
                        var vIcon = vComponentIcons[i];
                        vIcon.attr({
                            ...componentIconRect,
                            x: 34,
                            y: 24 * (i + 1) + 4
                        });
                        this.vel.append(vIcon);
                    }

                    var vComponentLabels = this.vComponentLabels;
                    for (var i = 0; i < numberOfComponents; i++) {
                        var vText = vComponentLabels[i];
                        var tx = 58;
                        var ty = 24 * (i + 2) - 8;
                        vText.attr({
                            ...componentText,
                            transform: 'translate(' + tx + ',' + ty + ')'
                        });
                        this.vel.append(vText);
                    }
                },

                onComponentClick: function (evt) {
                    var index = +V(evt.target).attr('data-index');

                    var model = this.model;
                    var numberOfComponents = model.prop('numberOfComponents');
                    var vComponents = this.vComponents;
                    for (var i = 0; i < numberOfComponents; i++) {
                        vComponents[i].attr({
                            fill: i === index ? '#dddddd' : "#fafafa"
                        });
                    }
                },

                onDblClick: function () {
                    this.model.prop('faded', !this.model.prop('faded'));
                }
            });

        // SEE COMMENTS BELOW REGARDING THIS COMMENTED CODE:
        //}, {
        //    markup: {
        //        body: V('rect').addClass('body'),
        //        bodytitle: V('text').addClass('bodytitle'),
        //        components: V('rect').addClass('components'),
        //        componentStatus: V('text').addClass('componentStatus'),
        //        componentIcons: V('rect').addClass('componentIcons'),
        //        text: V('text').addClass('text')
        //    }
        //});

    }
}

The Element is initialized like this:元素初始化如下:

    ngOnInit(): void {
        this.schematicElementService.InitializeDefinitions();
        this.graph = new joint.dia.Graph();

        this.paper = new joint.dia.Paper({
            model: this.graph,
            cellViewNamespace: joint.shapes.basic,
            el: $('#paper'),
            width: 2400,
            height: 2400,
            origin: { x: 600, y: 600 },
            gridSize: 1,
            // interactive: { addLinkFromMagnet: false },
            linkPinning: false
        });
    }

The element is added to the graph like this:元素被添加到图表中,如下所示:

        let nodeData = this.schematicElementService.GetNodeElement();
        this.graph.addCell(nodeData.node);

In a way different from the jsFiddle, the Markup is placed in the Element.extend() function rather than in the ElementView.extend() (as shown in the commented code of the ElementView.extend() ).与 jsFiddle 不同的是,Markup 被放置在Element.extend() function 而不是ElementView.extend()中(如ElementView.extend() () 的注释代码所示)。

Implemented as above, I get a couple 'boxes' appear, but since the functions in the ElementView are not used, it does not process things as I expect it to.如上所述实现,我得到了几个“框”,但由于没有使用 ElementView 中的功能,它不会像我期望的那样处理事情。 Ie there is no text and no multiple boxes because these are processed in the functions.即没有文本,也没有多个框,因为这些是在函数中处理的。

When I remove the markup from the Element.extend() and put it in the ElementView.extend() (ie uncomment the commented code above), I get the following error when processing this:当我从Element.extend()中删除标记并将其放入ElementView.extend() (即取消注释上面的注释代码),处理此错误时出现以下错误:

ERROR Error: dia.ElementView: markup required
    at child.renderMarkup (rappid.js:19452)
    at child.render (rappid.js:19483)
    at child.protoProps.render (rappid.js:18246)
    at child.confirmUpdate (rappid.js:19372)
    at child.updateView (rappid.js:29615)
    at child.updateViewsBatch (rappid.js:29812)
    at child.updateViews (rappid.js:29668)
    at child.requestViewUpdate (rappid.js:29539)
    at child.renderView (rappid.js:30305)
    at child.onCellAdded (rappid.js:29261)

None of the console.log() calls that I added to the functions EVER gets written to console, so none of those functions ever get called.我添加到函数中的console.log()调用都没有写入控制台,因此这些函数都不会被调用。 Defining my custom element in the Joint data structure, as in joint.shapes.custom = {} does not make a difference.在 Joint 数据结构中定义我的自定义元素,如joint.shapes.custom = {}并没有什么不同。 I have the same problem using either of the JointJS or the Rappid libraries.使用 JointJS 或 Rappid 库时,我遇到了同样的问题。

Does anyone see what I'm doing wrong here?有人看到我在这里做错了吗? I cannot figure out how to make this work.我无法弄清楚如何使这项工作。

Thanks in advance for any assistance you can provide.提前感谢您提供的任何帮助。

I'm not sure if this will work in your case, but you could try specifying the view to use when initialising the paper, with the elementView option:我不确定这是否适用于您的情况,但您可以尝试使用elementView选项指定初始化纸张时要使用的视图:

 this.paper = new joint.dia.Paper({
            model: this.graph,
            cellViewNamespace: joint.shapes.basic,
            elementView: this.schematicElementService.ElementView,
            ...

Also, I'm not sure if the element view should be a child of the element.另外,我不确定元素视图是否应该是元素的子元素。 In my case I put the element view in a separate variable.在我的例子中,我将元素视图放在一个单独的变量中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM