3

我是jointJs库的新手,我正在尝试将端口添加到我的自定义元素中,其中包含html代码。我按照本教程(http://www.jointjs.com/tutorial/html-elements)创建了我的元素。但是当我尝试向它添加端口时(基于本教程:http ://www.jointjs.com/tutorial/ports )它不起作用。我遇到的另一个问题是,当我单击空白纸时,我希望文本框(自定义形状上的文本区域)消失,并且只有带有其内容的标签在元素上保持可见。为此,我使用了以下代码(但它没有给我上述功能):

paper.on('blank:pointerdown', function(evt, x, y) { this.$box.find('textarea').toBack(); });

        this.model.on('cell:pointerclick', function(evt, x, y) {this.$box.find('textarea').toFront();});

我的整个代码如下:

<!DOCTYPE html>
<html>
<head>


<link rel="stylesheet" href="graph.css">

<script type="text/javascript" src="http://www.jointjs.com/downloads/joint.js" ></script>
<script src="http://www.jointjs.com/downloads/joint.shapes.devs.js" ></script>
<script src="http://www.jointjs.com/downloads/joint.shapes.devs.min.js" ></script>

</head>
<title>Test</title>

<body>
    <div id="myholder"></div>
</body>
<script>

    var graph = new joint.dia.Graph;

    var paper = new joint.dia.Paper({
        el: $('#myholder'),
        width: 1500,
        height: 700,
        model: graph
    });

    // Create a custom element.
    // ------------------------
    joint.shapes.html = {};
    joint.shapes.html.Element = joint.shapes.basic.Rect.extend({
        defaults: joint.util.deepSupplement({
            type: 'html.Element',
            attrs: {
                rect: { stroke: 'none', 'fill-opacity': 0 }
            }
        }, joint.shapes.basic.Rect.prototype.defaults)
   });

   // Create a custom view for that element that displays an HTML div above it.
   // -------------------------------------------------------------------------

    joint.shapes.html.ElementView = joint.dia.ElementView.extend({

        template: [
            '<div class="html-element">',
            '<button class="delete">x</button>',
            '<span id="lbl" value="Please write here"></span>', 
            '<textarea id="txt" type="text" value="Please write here"></textarea>',
            '</div>'
        ].join(''),

    initialize: function() {
        _.bindAll(this, 'updateBox');
        joint.dia.ElementView.prototype.initialize.apply(this, arguments);

        this.$box = $(_.template(this.template)());
        // Prevent paper from handling pointerdown.
        this.$box.find('input,select').on('mousedown click', function(evt) { evt.stopPropagation(); });


        // This is an example of reacting on the input change and storing the input data in the cell model.
        this.$box.find('textarea').on('change', _.bind(function(evt) {
            this.model.set('textarea', $(evt.target).val());
        }, this));
        this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
        // Update the box position whenever the underlying model changes.
        this.model.on('change', this.updateBox, this);
        // Remove the box when the model gets removed from the graph.
        this.model.on('remove', this.removeBox, this);

        this.updateBox();
    },


     render: function() {
        joint.dia.ElementView.prototype.render.apply(this, arguments);
        this.paper.$el.prepend(this.$box);
        this.updateBox();
        return this;
    },

    updateBox: function() {
        // Set the position and dimension of the box so that it covers the JointJS element.
        var bbox = this.model.getBBox();
        // Example of updating the HTML with a data stored in the cell model.
        paper.on('blank:pointerdown', function(evt, x, y) { this.$box.find('textarea').toBack(); });
        this.$box.find('span').text(this.model.get('textarea'));
        this.model.on('cell:pointerclick', function(evt, x, y) { this.$box.find('textarea').toFront(); });
        this.$box.css({ width: bbox.width, height: bbox.height, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' });
    },
    removeBox: function(evt) {
        this.$box.remove();
    }
}); 


// Create JointJS elements and add them to the graph as usual.
// -----------------------------------------------------------

var el1 = new joint.shapes.html.Element({ 
    position: { x: 600, y: 250 }, 
    size: { width: 200, height: 100 }, 
    inPorts: ['in'],
    outPorts: ['out'],
    attrs: {
        '.inPorts circle': { fill: 'gray'},
        '.outPorts circle': { fill: 'gray'}
    },
 textarea: 'Start writing'});

graph.addCells([el1]);

paper.on('cell:pointerdblclick', function(cellView, evt, x, y) {
   var el2 = new joint.shapes.html.Element({ position: { x: 600, y: 400 }, size: { width: 200, height: 100 }, textarea: 'Start writing'});

   var l = new joint.dia.Link({
        source: { id: el1.id },
        target: { id: el2.id },
        attrs: { '.connection': { 'stroke-width': 1, stroke: 'gray' } }
    });

    graph.addCells([el2, l]);
});


</script>
</html>

我已经搜索了很多这些问题的答案,但我没有成功找到简单而全面的答案。任何帮助将不胜感激。谢谢。

4

3 回答 3

8

我也是jointJs的新手,遇到了同样的问题,发现了这个线程。我已经尝试并成功地工作了。

您必须自定义元素的 css 以获得更好的视图。转到使用端口以了解更多有关端口的工作。

这是代码:

<!DOCTYPE html>
<html>
<head>


<link rel="stylesheet" href="http://www.jointjs.com/downloads/joint.min.css">
<style type="text/css">
  #myholder .html-element{
    position: absolute;
    margin-left: 8px;
    padding: 5px 0 10px 0;
    background-color: #fff;
    border: 1px solid #eee;
    border-radius: 5px;
    pointer-events: none;
    -webkit-user-select: none;
  }
</style>

<script type="text/javascript" src="http://www.jointjs.com/downloads/joint.min.js" ></script>
</head>
<title>Test</title>

<body>
    <div id="myholder"></div>
</body>
<script>

    var graph = new joint.dia.Graph;

    var paper = new joint.dia.Paper({
        el: $('#myholder'),
        width: 1500,
        height: 700,
        model: graph
    });

    // Create a custom element.
    // ------------------------
    joint.shapes.html = {};
    joint.shapes.html.Element = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
        markup: '<g class="rotatable"><g class="scalable"><rect/></g><g class="inPorts"/><g class="outPorts"/></g>',
        portMarkup: '<g class="port<%= id %>"><circle/></g>',
        defaults: joint.util.deepSupplement({
            type: 'html.Element',
            size: { width: 100, height: 80 },
            inPorts: [],
            outPorts: [],
            attrs: {
                '.': { magnet: false },
                rect: {
                    stroke: 'none', 'fill-opacity': 0, width: 150, height: 250,
                },
                circle: {
                    r: 6, //circle radius
                    magnet: true,
                    stroke: 'black'
                },

                '.inPorts circle': { fill: 'green', magnet: 'passive', type: 'input'},
                '.outPorts circle': { fill: 'red', type: 'output'}
            }
        }, joint.shapes.basic.Generic.prototype.defaults),
        getPortAttrs: function (portName, index, total, selector, type) {

            var attrs = {};
            var portClass = 'port' + index;
            var portSelector = selector + '>.' + portClass;
            var portCircleSelector = portSelector + '>circle';
            attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type), type: type } };
            attrs[portSelector] = { ref: 'rect', 'ref-y': (index + 0.5) * (1 / total) };
            if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
            return attrs;
        }
    }));


   // Create a custom view for that element that displays an HTML div above it.
   // -------------------------------------------------------------------------

    joint.shapes.html.ElementView = joint.dia.ElementView.extend({

        template: [
            '<div class="html-element">',
            '<button class="delete">x</button>',
            '<span id="lbl" value="Please write here"></span>', 
            '<textarea id="txt" type="text" value="Please write here"></textarea>',
            '</div>'
        ].join(''),

    initialize: function() {
        _.bindAll(this, 'updateBox');
        joint.dia.ElementView.prototype.initialize.apply(this, arguments);

        this.$box = $(_.template(this.template)());
        // Prevent paper from handling pointerdown.
        this.$box.find('input,select').on('mousedown click', function(evt) { evt.stopPropagation(); });


        // This is an example of reacting on the input change and storing the input data in the cell model.
        this.$box.find('textarea').on('change', _.bind(function(evt) {
            this.model.set('textarea', $(evt.target).val());
        }, this));
        this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
        // Update the box position whenever the underlying model changes.
        this.model.on('change', this.updateBox, this);
        // Remove the box when the model gets removed from the graph.
        this.model.on('remove', this.removeBox, this);

        this.updateBox();

        this.listenTo(this.model, 'process:ports', this.update);
        joint.dia.ElementView.prototype.initialize.apply(this, arguments);
    },


     render: function() {
        joint.dia.ElementView.prototype.render.apply(this, arguments);
        this.paper.$el.prepend(this.$box);
        // this.paper.$el.mousemove(this.onMouseMove.bind(this)), this.paper.$el.mouseup(this.onMouseUp.bind(this));
        this.updateBox();
        return this;
    },

    renderPorts: function () {
        var $inPorts = this.$('.inPorts').empty();
        var $outPorts = this.$('.outPorts').empty();

        var portTemplate = _.template(this.model.portMarkup);

        _.each(_.filter(this.model.ports, function (p) { return p.type === 'in' }), function (port, index) {

            $inPorts.append(V(portTemplate({ id: index, port: port })).node);
        });
        _.each(_.filter(this.model.ports, function (p) { return p.type === 'out' }), function (port, index) {

            $outPorts.append(V(portTemplate({ id: index, port: port })).node);
        });
    }, 

    update: function () {

        // First render ports so that `attrs` can be applied to those newly created DOM elements
        // in `ElementView.prototype.update()`.
        this.renderPorts();
        joint.dia.ElementView.prototype.update.apply(this, arguments);
    },

    updateBox: function() {
        // Set the position and dimension of the box so that it covers the JointJS element.
        var bbox = this.model.getBBox();
        // Example of updating the HTML with a data stored in the cell model.
        // paper.on('blank:pointerdown', function(evt, x, y) { this.$box.find('textarea').toBack(); });
        this.$box.find('span').text(this.model.get('textarea'));
        this.model.on('cell:pointerclick', function(evt, x, y) { this.$box.find('textarea').toFront(); });
        this.$box.css({ width: bbox.width, height: bbox.height, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' });
    },
    removeBox: function(evt) {
        this.$box.remove();
    }
}); 


// Create JointJS elements and add them to the graph as usual.
// -----------------------------------------------------------

var el1 = new joint.shapes.html.Element({ 
    position: { x: 600, y: 250 }, 
    size: { width: 170, height: 100 },
    inPorts: ['in'],
    outPorts: ['out'],
    textarea: 'Start writing'
  });

var el2 = new joint.shapes.html.Element({ 
    position: { x: 600, y: 400 },
    size: { width: 170, height: 100 },
    inPorts: ['in'],
    outPorts: ['out'],
    textarea: 'Start writing'
  });

graph.addCells([el1, el2]);


</script>
</html>
于 2014-10-06T17:55:26.630 回答
2

我问了一个没有人回答的问题。这就是我如何在单击空白纸时使 textarea 消失并在单击单元格时出现的方法:首先我认为我必须通过 javascript 中的 jsonJS 事件来解决它。但我发现有一个非常简单的解决方案。我只需要在 css 样式中使用悬停功能并将不透明度从 0 更改为 1 当您将鼠标悬停在框上时(在您的 css 文件中):

.html-element textarea {
   position: absolute;
   bottom: 0;
   left: 0;
   right: 0;
   height: 60px;
   width: 150px;
   border: none;
   color: #333;
   background-color: white;
   padding: 5px;
   margin: 5px;
   opacity:0;

}

.html-element textarea:hover {

   opacity:1;
}
于 2014-10-09T13:44:26.840 回答
1

rzkmr 的回答对我有用,+1'd 他的回答。(谢谢!)
在他的示例中,要允许使用 textarea,请将其添加到 css:


    .html-element select,
    .html-element input,
    .html-element textarea,
    .html-element button {
       /* Enable mouse interaction. */
       pointer-events: auto;   
    }
于 2014-10-28T00:20:10.773 回答