SVG图形中的文本区域

4

使用Joint JS在SVG中创建了一个文本区域。但是,我无法在文本区域中输入任何文本。如何使文本区域可编辑?

代码:

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<%=1%>"><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 + 1) * (10 / 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]);

同时,是否有可能根据文本区域内的文本来缩放SVG形状?


我想你应该使用HTML文本区创建自定义元素。我不确定它是否支持所有更新的浏览器。最好咨询Roman或Dave。 - user4414924
http://stackoverflow.com/users/2921495/roman - user4414924
你介意创建一个关于根据文本大小调整元素尺寸的单独问题吗? - Roman
1个回答

2
我假设您正在使用JointJS HTML教程中的CSS样式表(http://jointjs.com/tutorial/html-elements)。
请注意,.html-elementpointer-events 被设置为 none。这样设置后,所有事件都会传播到(JointJS)SVG元素下的HTML元素。因此,画布知道与哪个元素交互,例如可以开始拖动它。
.html-element {
   pointer-events: none;
}

我建议通过添加以下CSS规则来创建TextArea的异常情况。
.html-element textarea {
   pointer-events: all;
}

能否使用SVG文本并将内容编辑设置为true,而不是使用HTML文本区域? - user2046417
是和不是。 “不是”因为SVG文本元素没有contentEditable功能。 “是”因为存在一个hacky解决方案 - 请参见https://github.com/artursapek/mondrian/issues/12和https://dev59.com/dGIj5IYBdhLWcg3wRjSr。显然,光标存在一些问题,而且我不确定跨浏览器的兼容性。 SVG 2.0一旦实现可能会有所帮助。 - Roman
请检查一下这个链接:http://rigrr.rapilabs.com/,其中圆角矩形可以输入文本。我无法弄清楚它是如何工作的,因为SVG规范没有提到可编辑文本。 - user2046417
1
Rapilabs 在 SVGTextElement 前面绘制了一个 HTML 输入,并将 SVGTextElement 的不透明度设置为 0。 - Roman
1
W3C的链接讨论了SVG Tiny 1.2,它是SVG 1.1的一个子集,具有几个附加功能。它不能应用于这里。 - Roman
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接