Svg(Snap.svg)创建对话气泡

7

我正在创建一个聊天程序,在屏幕上移动的一些图形与其他人聊天。

完成这个项目的最后一件事情之一是每当有人说话时,它会被放入一个可缩放的对话气泡中。

因为我很少使用SVG,并且这是我第一个真正的“游戏”项目,所以我想,“让我们使用一些CSS来确保它的正确缩放”。

所以我写了以下CSS:

    .bubble {
    background-color: #eee;
    border: 2px solid #333;
    border-radius: 5px;
    color: #333;
    display: inline-block;
    font: 16px/24px sans-serif;
    padding: 12px 24px;
    position: relative;
}
.bubble:after,
.bubble:before {
    border-left: 20px solid transparent;
    border-right: 20px solid transparent;
    border-top: 20px solid #eee;
    bottom: -20px;
    content: '';
    left: 50%;
    margin-left: -20px;
    position: absolute;
}

/* Styling for second triangle (border) */

.bubble:before {
    border-left: 23px solid transparent;
    border-right: 23px solid transparent;
    border-top: 23px solid;
    border-top-color: inherit; /* Can't be included in the shorthand to work */
    bottom: -23px;
    margin-left: -23px;
}

很遗憾,那并没有奏效。我后来发现这是因为SVG不支持所有的CSS属性。所以现在我有些困惑了?我不太确定如何在SVG中创建可缩放的文字气泡,希望你们中的一位可以友善地指点我正确的方向。
我已经尝试过的SVG路径
我成功地创建了一个非常小的SVG路径,但我不确定如何使它变大并填充文本:
    var mesasgeBox = chatSvg.path("M 200.444444444444446,200v-6h10.444444444444446v6h-4l-3.1111111111111107,1.6222222222222236l0.11111111111111072,-1.6222222222222236Z");

你标签了 Snap.svg,你在 Snap 中尝试过什么? - Ian
@Ian,我已经添加了SVG路径。 - Marc Rasmussen
@MarcRasmussen请告诉我们你喜欢哪个提出的解决方案,以及为什么。谢谢。 - Jan Franta
6个回答

4
以下源代码需要一个位置 (x/y) 来知道显示的位置,并且需要一个最大宽度来包装文本。它是作为插件编写的,因此您可以轻松使用。我还没有进行优化,通过按 font-size 缓存字母宽度可以提高性能。
字体换行代码基于这个解决方案How to either determine SVG text box width, or force line breaks after 'x' characters?
请在插件中替换 paper.rect 以使用您喜欢的气泡布局。
Snap.plugin(function (Snap, Element, Paper, glob) {
     Paper.prototype.bubbletext = function (x, y, txt, maxWidth, attributes) {

        var svg = Snap();
        var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.";
        var preText = svg.text(0, 0, abc);
        preText.attr(attributes);
        var letterWidth = (preText.getBBox().width / abc.length);
        svg.remove();

        var words = txt.split(" ");
        var widthCalc = 0, activeLine = 0, lines=[''];
        for (var letterCount = 0; letterCount < words.length; letterCount++) {

           var l = words[letterCount].length;
           if (widthCalc + (l * letterWidth) > maxWidth) {
              lines.push('');
              activeLine++;
              widthCalc = 0;
           }
           widthCalc += l * letterWidth;
           lines[activeLine] += words[letterCount] + " ";
        }

        var padding = 10;

        var t = this.text(x+padding, y+15+padding, lines).attr(attributes);

        t.selectAll("tspan:nth-child(n+2)").attr({
           dy: "1.2em",
           x: x+padding
        });

        var boxHeight = t.node.clientHeight + (padding * 3);
        var messageBox = this.path("M " + (x-padding) + "," + (y-padding+boxHeight) + "v-" + boxHeight + "h" +  (t.node.clientWidth + (padding*3)) + "v"+boxHeight+"h-6l-9,15l0,-15Z");
        messageBox.attr({
            fill:"rgba(0, 0, 255, .3)"
        });
        t.before(messageBox);
        return t;
     };
  });

var div = document.querySelector('div.wrap');
var bubble = Snap('100%','100%').attr({ viewBox: '0  0 200 200' });;
bubble.bubbletext(0, 0, "Hallo Mike how are you. These text is auto wraped and the bubble size automaticaly. The svg result is also scaleable. Please change this text to test.", 155,
    { "font-size": "15px", "fill": "#000"});
div.appendChild(bubble.node);

CODEPEN

更新

将您的气泡布局添加到Codepen示例中。

更新2
我更新了源示例。


嘿,伙计,谢谢你的回复。能否去掉使其变得越来越大的动画效果? - Marc Rasmussen
@MarcRasmussen,已经完成了。你只需要改变元素的顺序就可以了。就这样。看一下Codepen的例子。 - Jan Franta
在当前的Chrome或Firefox中不起作用。文本会像动画一样不断增长,气泡永远无法完全包含它。 - John Hatton

3

没有特定的填充文本方法,但您可以自己放置并进行动画处理。

这将创建一个泡泡,并随着文本执行相同的动画。

缩放变换可以写成'sX,Y,CX,CY'。CX/CY是缩放的中心点。Snap会自动尝试围绕中心缩放(不像普通的SVG scale(x,y))。

因此,'s20,20'将在x和y方向上使元素缩小20倍。

var b = s.path("M 200.444444444444446,200v-6h10.444444444444446v6h-4l-3.1111111111111107,1.6222222222222236l0.11111111111111072,-1.6222222222222236Z").attr({ fill: 'gray' });

b.animate({ transform: 's10,10' }, 2000)

var t = s.text(190,200,'stuff!').attr({ stroke: 'yellow', fill: 'yellow', transform: 's0.2,0.2'})
t.animate({ transform: 's2,2'}, 2000)

jsfiddle

这只需要微调一下样式和对齐方式即可。

注:此处的微调指的是根据需求进行适当的调整。

这正是我需要的!有没有办法使角落更圆润?! - unconditionalcoder
将路径改为圆角,因此您需要在其中添加一些曲线。您可能会发现已经有一个svg完成了,或者需要使用编辑器进行操作。 - Ian

2

如果不使用SnapSVG,您可以:

创建一些SVG(我使用了Illustrator):

    <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 200 115.9" enable-background="new 0 0 150 115.9" xml:space="preserve">
<g>
    <g>
        <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="33.5436" y1="98.5111" x2="92.6585" y2="11.8584">
            <stop  offset="0" style="stop-color:#FFFFFF"/>
            <stop  offset="1" style="stop-color:#D1D3D4"/>
        </linearGradient>
        <path fill="url(#SVGID_1_)" stroke="#000000" stroke-miterlimit="10" d="M138.5,14.8c-7.8-2.2-33.8-3.8-64.7-3.8
            c-31.2,0-57.4,1.6-64.9,3.8c-0.4,0.1-0.8,0.2-1.1,0.4c-0.3,0.1-0.6,0.3-0.7,0.4c-1.5,1-2.4,2.7-2.4,4.6L14,80.4
            c0.3,2.6,1.6,4.4,3.4,5.1c1.7,0.8,5.9,1.6,11.8,2.2l9.7,0.8c6.6,0.4,14.4,0.7,22.8,0.8c-1.2,6.9,0.4,9.1-4,13.3
            c-8.7,8.3-14.1,7.7-14.1,7.7c1.4,0.5,11,1.7,20-4.8c6.9-4.9,6.1-8.4,7.7-16.2c0,0,0,0,0,0c28.4,0,51.8-1.9,54.5-4.3
            c1.4-0.9,2.4-2.6,2.8-4.7l14.6-60.2C143.1,17.5,141.1,15.3,138.5,14.8z"/>
        <g>
            <path fill="#E2E2E2" d="M138.5,14.8c-7.8-2.2-33.8-3.8-64.7-3.8c-31.2,0-57.4,1.6-64.9,3.8c-0.4,0.1-0.8,0.2-1.1,0.4
                c-0.3,0.1-0.6,0.3-0.7,0.4c-0.4,0.2-0.7,0.5-1,0.8c0.1,0,0.2-0.1,0.2-0.1C6.6,16.2,7,16.1,7.4,16c7.5-2.2,33.7-3.8,64.9-3.8
                c30.9,0,56.9,1.6,64.7,3.8c2.6,0.5,4.6,2.7,4.6,5.4L127,81.6c-0.3,1.6-0.9,3-1.8,3.9c0.2-0.1,0.4-0.2,0.5-0.3
                c1.4-0.9,2.4-2.6,2.8-4.7l14.6-60.2C143.1,17.5,141.1,15.3,138.5,14.8z"/>
        </g>
    </g>
</g>
<text id="bubbleText" transform="matrix(1 0 0 1 21.6668 57.9542)" font-family="'MyriadPro-Regular'" font-size="15.3912">POW! Shazaam. </text>
</svg>

通过JS操作文本

document.getElementById('bubbleText').textContent = "new text";

使用SVG根元素上的“viewBox”属性缩放SVG

JSFiddle


2
如果您将SVG的heightwidth设置为100%,则SVG节点将响应其容器,并且使用viewbox可以控制内部元素的视图;
然后svg将对容器应用的任何缩放做出响应。

pen


我将你的缩放功能添加到我的笔例中。 - Jan Franta
1
感谢您。希望这符合要求。 - Jan Franta

2
一个短的SVG嵌入到一个
中。 使用jQuery来动画化大小和位置。 回调函数用于使单词可见,第二行使用了.fadeIn()方法。
希望这可以帮助您。

$('div').append('<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0.00000000" y="0.00000000" width="100%" height="100%" id="svg3" viewbox="0 0 1000 600" >  <path fill="#FFFFFF" stroke="#000000" stroke-width="10" d="M916.902,397.331c14.126,0,17.344-9.739,17.344-9.739   c0-27.635,7.992-42.357,26.927-42.357c0,0,13.702,1.668,13.702-14.946c0-0.001,0.619-43.408-1.901-141.244   c-2.514-97.836-9.537-109.333-9.537-109.333c0-14.125-9.129-13.284-9.129-13.284c-24.67,0-53.406,4.151-53.406-30.893   c0,0,1.558-11.866-15.041-11.866c0,0-159.78-14.301-423.823-14.301c-264.041,0-375.12,2.352-375.12,2.352   c-14.125,0-13.284,9.136-13.284,9.136c0,22.479-13.575,42.622-30.319,42.622c0,0-13.705,0.341-13.705,16.949   c0,0-4.551,60.914-4.551,117.724c0,56.808,4.551,126.899,4.551,126.899c0,14.125,9.127,13.28,9.127,13.28   c24.9,0,29.944,10.568,29.944,30.322c0,0,1.038,15.744,25.709,15.744l248.677,5.155c0,0,46.81,25.855,64.76,39.665   c17.952,13.808,27.714,26.235,12.526,41.426c-6.669,6.666-11.966,12.474-9.571,21.187c2.277,8.256,26.797,22.168,29.903,23.746   c0.261,0.127,61.957,30.323,84.796,41.37c16.646,8.047,33.288,16.074,49.292,25.362c2.152,1.253,14.271,9.614,16.804,7.089   c2.484-2.479-11.174-12.959-12.823-14.315c-9.084-7.442-16.206-16.462-24.158-25.027c-12.481-13.465-25.133-26.788-37.746-40.133   c-7.044-7.464-13.884-15.167-21.144-22.43c-1.791-1.79-1.476-4.571,0.699-7.001c7.682-8.531,25.246-28.013,27.384-30.14   c2.739-2.731-1.814-7.121-1.814-7.121l-62.959-51.678L916.902,397.331z"/> <text x="200" y="200" font-size="72" color="blue" id="myText" style="display: none;" >Hello Stackoverflow</text> <text x="200" y="300" font-size="72" color="blue" id="myText2" style="display: none;" >Delayed text</text> </svg>');

$('div').draggable({
    handle: 'rect'
});

$('div').animate({ // shrink it
    width: "100px",
    height: "60px",
    top: "240px",
    left: "220px"
}, 0) 
.animate({ // animate to full size
    width: "500px",
    height: "300px",
    top: "0px",
    left: "0px"
}, 2000, function() { // show text
    // Animation complete.

     $('#myText').show();
     $('#myText2').fadeIn('slow');
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div style="width:500px; height:300px; ">
</div>


1
你可能不想使用SVG,除非你的显示屏已经是SVG为中心。 气泡将会移动以避免遮挡面部和控件,根据文本缩放,而SVG文本则是自己的困难动物。 SVG的优点仅限于其可伸缩性,在DOM中进行操作以及需要嵌套变换的应用程序。
相反,考虑使用纯CSS制作气泡,如此处所示。 或者,您可以预先渲染一组气泡图形,根据需要拉伸,并在其上书写文本。 纯CSS最适合快速弹出,而预渲染图形最适合期望小思考气泡,动画或其他可爱添加的情况。

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