I am creating a chat program with some figures on the screen moving around chatting with other people.
One of the last things I need to complete this project is when ever a person says something it is put into a scaleable speech bubble.
Since I'm very new at using SVG and this is my first real "Game" project I thought "Let's use some CSS to make sure that it scales correctly"
So I made the following 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; }
But sadly that didn't work. I later found out it is because SVG does not support all CSS properties. So now I'm kind of at a lost? I am not quite sure how to create a scalable speech bubble in SVG and I was hoping one of you might be kind enough to point me in the right direction.
SVG path
I have tried:
I managed to create a very small SVG path however I'm unsure how to make it bigger and make it it filled with text:
var mesasgeBox = chatSvg.path("M 200.444444444444446,200v-6h10.444444444444446v6h-4l-3.1111111111111107,1.6222222222222236l0.11111111111111072,-1.6222222222222236Z");
6 Answers
Answers 1
There is no specific fill with text method, but you can place this yourself and animate.
This would create a bubble and animate with text doing the same thing.
A scale transform, can be written as 'sX,Y,CX,CY'. CX/CY being a centre point to scale around. Snap will automatically try and scale this around the centre (unlike normal svg scale(x,y)).
So 's20,20' will scale the element by 20 in both x and y directions.
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)
It will just need tweaking for how you want it to look and any alignment.
Answers 2
A short SVG embedded into a div
. jQuery is used to animate the size + position. A callback is used to make the words visible and the 2nd liner uses .fadeIn()
.
Hope it helps.
$('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>
Answers 3
While not using SnapSVG you could: Create some SVG (I used 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>
Manipulate the text via JS
document.getElementById('bubbleText').textContent = "new text";
Scale the SVG with the 'viewBox' property on the SVG root element
Answers 4
if you set the svg height
and width
to 100%
the svg node will be responsive to it's container and with viewbox
you can control the view of the inside elements;
the svg
will then be responsive to whatever scaling applied to container .
pen
Answers 5
The source below require a position (x/y) to know where to appear and a max width for text wrapping. It's written as plugin, so you can use it easy. I have not optimized it and the performance can be raised by caching the letter width by font-size.
The font wrapping code is based on this solution here How to either determine SVG text box width, or force line breaks after 'x' characters?
Please replace the paper.rect inside the plugin with your prefered bubble layout.
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 paddingHeight = 20; var paddingWidth = 10; var r = this.rect(x-paddingWidth, y-paddingHeight, 0, 0); var t = this.text(x, y, lines).attr(attributes); t.selectAll("tspan:nth-child(n+2)").attr({ dy: "1.2em", x: x }); r.attr({ height: (t.node.clientHeight + paddingWidth), width: (t.node.clientWidth + paddingHeight), fill: "rgba(0, 0, 255, .3)" }); return t; }; }); var s= Snap(); var bubble = s.bubbletext(150, 50, "A very long Text with a auto resized box behind. The text will wrap after a defined max width.", 155, { "font-size": "20px", "fill": "#000"});
And a playground on CODEPEN
UPDATE
Add your bubble layout to codepen example.
Answers 6
You probably don't want to use SVG unless the rest of your display is already SVG centric. The speech bubble will be moving around ot avoid occulding faces and controls, scaling for the text, and SVG text is its own suffering animal. The advantages of SVG are limited to its scalability, ability to be manipulated in the DOM, and applications where nested transformations are necessary.
Instead consider making speech bubbles in pure CSS as seen here. Alternately, you can prerender a set of speech bubble graphics, stretch as necessary, and write text on top of them. Purr CSS works best for quick pop-outs while prerendered graphics works best if you expect little thought bubbles, animations, or other cute additions.
0 comments:
Post a Comment