Svg (snapsvg) 创建一个对话泡泡
Svg (snapsvg) creating a speech bubble
我正在创建一个聊天程序,屏幕上有一些数字在四处移动,与其他人聊天。
我需要完成这个项目的最后一件事是,当有人说某事时,它会被放入一个可扩展的对话泡泡中。
因为我在使用 SVG 方面还很陌生,这是我第一个真正的 "Game" 项目,所以我认为 "Let's use some CSS to make sure that it scales correctly"
所以我做了以下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 path
我试过了:
我设法创建了一个非常小的 SVG 路径,但是我不确定如何将其变大并填充文本:
var mesasgeBox = chatSvg.path("M 200.444444444444446,200v-6h10.444444444444446v6h-4l-3.1111111111111107,1.6222222222222236l0.11111111111111072,-1.6222222222222236Z");
没有具体的填充文本的方法,但你可以自己放置并制作动画。
这将创建一个气泡并使文本具有相同的效果。
一个尺度变换,可以写成'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)
它只需要根据您想要的外观和任何对齐方式进行调整。
嵌入 div
的短 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 Whosebug</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>
在不使用 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
下面的源代码需要一个位置 (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);
更新
将气泡布局添加到代码笔示例中。
更新 2
我更新源示例。
如果您将 svg height
和 width
设置为 100%
svg 节点将响应它的容器并且使用 viewbox
您可以控制视图内部元素;
然后 svg
将对应用于容器的任何缩放做出响应。
pen
您可能不想使用 SVG,除非您显示的其余部分已经以 SVG 为中心。对话泡泡会四处移动以避免遮挡面孔和控件,缩放文本,SVG 文本本身就是受苦的动物。 SVG 的优势仅限于其可扩展性、在 DOM 中进行操作的能力以及需要嵌套转换的应用程序。
而是考虑在纯 CSS as seen here 中制作对话泡泡。或者,您可以预渲染一组语音气泡图形,根据需要进行拉伸,然后在其上书写文本。 Purr CSS 最适合快速弹出窗口,而预渲染图形最适合如果您不希望有小思想泡泡、动画或其他可爱的附加内容。
我正在创建一个聊天程序,屏幕上有一些数字在四处移动,与其他人聊天。
我需要完成这个项目的最后一件事是,当有人说某事时,它会被放入一个可扩展的对话泡泡中。
因为我在使用 SVG 方面还很陌生,这是我第一个真正的 "Game" 项目,所以我认为 "Let's use some CSS to make sure that it scales correctly"
所以我做了以下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 path
我试过了:
我设法创建了一个非常小的 SVG 路径,但是我不确定如何将其变大并填充文本:
var mesasgeBox = chatSvg.path("M 200.444444444444446,200v-6h10.444444444444446v6h-4l-3.1111111111111107,1.6222222222222236l0.11111111111111072,-1.6222222222222236Z");
没有具体的填充文本的方法,但你可以自己放置并制作动画。
这将创建一个气泡并使文本具有相同的效果。
一个尺度变换,可以写成'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)
它只需要根据您想要的外观和任何对齐方式进行调整。
嵌入 div
的短 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 Whosebug</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>
在不使用 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
下面的源代码需要一个位置 (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);
更新
将气泡布局添加到代码笔示例中。
更新 2
我更新源示例。
如果您将 svg height
和 width
设置为 100%
svg 节点将响应它的容器并且使用 viewbox
您可以控制视图内部元素;
然后 svg
将对应用于容器的任何缩放做出响应。
pen
您可能不想使用 SVG,除非您显示的其余部分已经以 SVG 为中心。对话泡泡会四处移动以避免遮挡面孔和控件,缩放文本,SVG 文本本身就是受苦的动物。 SVG 的优势仅限于其可扩展性、在 DOM 中进行操作的能力以及需要嵌套转换的应用程序。
而是考虑在纯 CSS as seen here 中制作对话泡泡。或者,您可以预渲染一组语音气泡图形,根据需要进行拉伸,然后在其上书写文本。 Purr CSS 最适合快速弹出窗口,而预渲染图形最适合如果您不希望有小思想泡泡、动画或其他可爱的附加内容。