How to detect if text flows outside bounding box - javascript

I have a situation beyond my immediate control (library-related) where text in an HTML div goes beyond its enclosing bounding box. I give a simple example below, although in my case it is a div within a <foreignObject> inside a <g> within an <svg>...
In the example below, is there a way to programmatically detect if the text goes beyond its bounding box? Getting the size of the enclosed <div> and its associated parent seems to return the same width, which is NOT the width of the text.
<!doctype html>
<html lang="">
<head>
<style>
.container {
background: yellow;
border: 2px solid black;
width: 200px;
height: 100px;
}
.tooBig {
white-space: nowrap;
}
</style>
<script>
function figureOutSizes() {
let container = document.getElementById("my-container");
let contBound = container.getBoundingClientRect();
console.log(`Container size: ${boundToString(contBound)}` );
let tooBig = document.getElementById("tooBig");
let bigBound = tooBig.getBoundingClientRect();
console.log(`text size: ${boundToString(bigBound)}` );
}
function boundToString(rect) {
return `rect(w=${rect.width}, h=${rect.height})`;
}
</script>
<meta charset="utf-8">
<title>Out of bounds</title>
</head>
<body>
<div id="my-container" class="container" >
<div id="tooBig" class="tooBig">This line is too big for its containing div! What am I going to do?</div>
</div>
<div>
<button onclick="figureOutSizes();">Get sizes</button>
</div>
</body>
</html>

You can use scrollWidth and scrollHeight instead of getBoundingClientRect:
function figureOutSizes() {
let container = document.getElementById("my-container");
let contBound = container.getBoundingClientRect();
console.log(`Container size: ${boundToString(contBound)}`);
let tooBig = document.getElementById("tooBig");
let bigBound = {
width: tooBig.scrollWidth,
height: tooBig.scrollHeight
};
console.log(`text size: ${boundToString(bigBound)}`);
}
function boundToString(rect) {
return `rect(w=${rect.width}, h=${rect.height})`;
}
.container {
background: yellow;
border: 2px solid black;
width: 200px;
height: 100px;
}
.tooBig {
white-space: nowrap;
}
<div id="my-container" class="container">
<div id="tooBig" class="tooBig">This line is too big for its containing div! What am I going to do?</div>
</div>
<div>
<button onclick="figureOutSizes();">Get sizes</button>
</div>

Getting only text width
If you only want to detect if a string goes out of its parent element, the best way is to do it with the jQuery element.width() method where you put the string inside a span, because the div element automatically gets a 100% width by default.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id='tooBig' style='white-space: nowrap;'>This string is too long ...</span>
<script>
var x = $('#tooBig').width();
console.log("Text width: "+x);
</script>
Now, you can compare it to the container's width and check if the string is wider than its parent.
If you want to avoid wrapping, add the white-space: nowrap; CSS style for the parent span or use character encoding instead of spaces.
Wrap string automatically with CSS
I suppose your purpose is not only to detect if the text flows out of a div, rather to wrap the string, so there is a quite elegant CSS method for this. The technique uses flexbox, test-overflow: ellipsis and overflow: hidden and the behaviour of string overflow. You do not need to use any kind of JavaScript for it, the text wraps and get the ... ending automatically.
/* Text is a header now,
so need to truncate there for it to work */
.flex-child > h2 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Text is directly within flex child,
so doing the wrapping here */
.flex-child {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
<div class="flex-parent">
<div class="flex-child">
<h2>Resize the window to see how this very very long text gets resized...</h2>
</div>
</div>
Reference
CSS Flexbox Resize
jQuery text width

Related

Container with lots of content starts at a specific height, grows to fit content, and then shrinks on clicks

I am trying to make a container that holds some text and images, and starts out at a certain size, say 48px. Upon clicking I want the container to grow to fit the contents, and on a second click reshrink down to 48px. The main issue is I don't want to set the height for the full size container, I would like the container to automatically resize to fit the content.
I have figured out how to start the blog at full size, shrink and regrow, but I can't figure out a way to have it start small, grow, and shrink again.
const hoistingId = document.getElementById('hoisting')
function enlargeBlogItem() {
if(hoistingId.style.height===''){
hoistingId.style.height = '3rem';
} else {
hoistingId.style.height = '';
}
}
hoistingId.addEventListener('click', enlargeBlogItem)
You can use overflow: hidden; on the parent element to ensure that the child elements are inside the parent and not overlapping and then use a JavaScript function to handle the size changes. Attribute attr-small is used to store the original value of height. By removing the height attribute from the style of the parent it will default to wrapping the children.
function toggleSize(el){
const originalSize = el.getAttribute('attr-small');
if(el.style.height === originalSize) {
el.style.removeProperty('height');
} else {
el.style.height = originalSize;
}
}
#container {
border: 1px solid;
width: 200px;
overflow: hidden;
}
#container:hover {
cursor: pointer;
}
.foo {
width: 90px;
height: 90px;
background-color: red;
display: inline-block;
margin-left: 5px;
margin-top: 5px;
}
<div id='container' onclick='toggleSize(this)' attr-small='48px' style='height:48px;'>
<div class='foo'></div>
<div class='foo'></div>
<div class='foo'></div>
<div class='foo'></div>
<div class='foo'></div>
<div class='foo'></div>
</div>

How to break line automatically after slash?

I have a div on the left and a canvas on the right, both filling the whole screen. Depending on the item I point to in the canvas, I show some information on the div (element.innerHTML = '...'). The problem is, some texts are too long and get hidden to the right side of the div (I don't want to use a scrollbar).
Usually the long text is composed of slash-separated names, like name1/name2/name3. If the slash separated the text to a new line, my problem would be solved, but it doesn't. Some possible solutions would be:
1) substitute '/' with '/ ', but it gets ugly if the text fits in a single line. For the same reason, I can't add \n to the html. Also, this text is meant to be copied, so even adding some styling to hide the space is not what I need.
2) substitute '/' with another separator character that automatically breaks the line (are hyphens my only friend here? They don't look appropriate for my case).
3) use overflow-wrap: break-word, but it will break the word in the middle, and I prefer it to be broken right after the slash.
4) automatically increase the div width without messing with the canvas position and size (body is using flex-direction:row). That would be the best solution, I think, because it would also solve the rarest cases where the problem is not with the slash.
I made a jsfiddle to illustrate, you can see that some slashes break the text, while others don't (and the text breaks before the slash, which I think is ugly. Anyway, if I have to accept the text being broken before the slash, it still needs to break before ALL the necessary slashes!)
HTML
<body>
<div id='data'>
<button onclick='c()'>
Get Text
</button><br>
<br>
Default text.<br>
<br>
<span id='text'></span>
</div>
<canvas id='canv'>
</canvas>
</body>
CSS
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
overflow: hidden;
}
#data {
padding:10px;
background-color: #CCF;
overflow-y:auto;
overflow-x:hidden;
}
#canv {
background-color: #CFC;
}
JavaScript
var data = document.getElementById('data');
var canv = document.getElementById('canv');
canv.width = window.innerWidth - data.offsetWidth;
canv.height = window.innerHeight;
function c() {
var text = document.getElementById('text');
text.innerHTML = 'longname1/longname2/longname3/longname4';
}
You can wrap the slashes using span and apply some styling to make them close to text:
var data = document.getElementById('data');
var canv = document.getElementById('canv');
canv.width = window.innerWidth - data.offsetWidth;
canv.height = window.innerHeight;
function c() {
var text = document.getElementById('text');
text.innerHTML = 'longname1<span>/</span> longnam<span>/</span> longname3<span>/</span> longname4<span>/</span> lllllllll<span>/</span> lon<span>/</span> aa';
}
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
overflow: hidden;
}
#data {
padding: 10px;
background-color: #CCF;
overflow-y: auto;
overflow-x: hidden;
}
#canv {
background-color: #CFC;
}
#text span {
letter-spacing: -4px;
}
<body>
<div id='data'>
<button onclick='c()'>
Get Text
</button>
default text
<br>
<br>
<div id='text'></div>
</div>
<canvas id='canv'>
</canvas>
</body>

Cells data Wrapping in Html or css or Scripts

I have to display a sentence "some of the transaction processed successfully" but the td size is less to accommodate this. So its height is changing. I don't want to use nowrap also since it changes the width. I need to Display some thing like this "Some of the transaction...." how to achieve this.? any CSS or script 'll help me.. thanks in advance.
Current Status: Some of the transaction processed successfully
Expected: Some of the transaction....
You can use CSS text-overflow: ellipsis;:
.myDiv {
border: 1px solid black;
text-align: center;
text-overflow: ellipsis; /* Adds dots in the end on overflow */
white-space: nowrap; /* Disallows line break */
overflow: hidden; /* Hides overflowing text */
}
<div class="myDiv" style="width: 100px;">
Very long text very long text very long text
</div>
<div class="myDiv" style="width: 200px;">
Very long text very long text very long text
</div>
<div class="myDiv" style="width: 500px;">
Very long text very long text very long text
</div>
Use text-overflow: ellipsis with overflow: hidden and white-space: nowrap and fixed width in pixels.
Restrict by width.
div {
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
}
<div>Some of the transaction processed successfully</div>
Using Javascript substring.
Restrict by number of characters.
var div = document.getElementById('message'),
message = div.innerHTML.trim();
div.innerHTML = message.length > 20 ? message.substr(0, 20) + '...' : message;
<div id="message">Some of the transaction processed successfully</div>
For table elements, you need to add div inside td. Check Demo.

Get dimensions of text block via JavaScript, not the size of container's `getBoundingClientRect`

I want to get the size of text inside a container. Let's consider general case when the container has padding and border.
The problem is that getBoundingClientRect returns the size of text PLUS left border and padding, in case the text overflows. Otherwise it returns just the size of border box of the container.
You can get the width if you create a placeholder div with all of the same text formatting options and find it's width.
For instance, I will create a div with the class .hidden that has the same attributes as the original div.
div.container
{
font-size: 16px;
}
div.hidden
{
font-size: 16px;
display: none;
}
Then, using jQuery, copy the contents of .container to .hidden and find the width of .hidden:
$(function(){
$("div.container").each(function(){
$("body").append("<div class='hidden'>"+$(this).html()+"</div>");
var width = $("div.hidden").width();
$("div.width").html("Actual width: "+width+"px");
$("div.hidden").remove();
});
});
JSFiddle
Interesting! You could use javascript to clone the text inside of an empty element offscreen that has 0 padding/margin/border. Then you could get the width of that element.
var txt = document.getElementById('fixed').innerHTML,
clone = document.getElementById('clone');
clone.innerHTML = txt;
var width = clone.offsetWidth;
document.getElementById('output').innerHTML = width;
#fixed {
width: 8em;
height: 8em;
border: .5em solid red;
}
#clone {
margin: 0;
padding: 0;
border: 0;
position: fixed;
left: -9999px;
}
<div id="fixed">asdfkjahsdflkahjsdflkjhasdljfhalsdkjfhalsdkjfhalsdkjfhalksdhjflasd</div>
<div id="clone"></div>
Width of text: <span id="output"></span>
People who had answered here came with a brilliant idea of wrapping the text into a <div> having zero margin, border and padding;
I just developed the idea further. I place the div inside the container, making the text have exactly the same style as it had without wrapper.
JsFiddle
This solution will work almost everywhere. It can be broken by not very encouraged way of writing CSS, like
.container div b {
padding: 5px; /* firing only when test is run */
}
If you do not code CSS in you project like that, you are the lucky one to use my snippet )

Fixed size of div element

I am trying to create a div element with fixed size in html. My problem is, the above div receives input text from backbone. The size of text is unknown, so every time that the transmitted text is big, automatically the size of the div is change. How is it possible to display only the first words of the text that fit in the predefined bounding box of the div???
My css code
.hashTagsCloud {
max-width: 500px;
max-height: 400px;
overflow: hidden;
}
And html code:
<div class= "hashTagsCloud span4 offset1 "> //bootstrap
<div id="profiles> //backbone view
<script id="profileTemplate" type="text/template">//backbone template
</script>
</div>
</div>
I take data with getElementById.
You can use the overflow: hidden; property, granted that you set a width and height on the div already.
<style type='text/css'>
.text {
width: 100px;
height: 18px;
overflow: hidden;
white-space: pre-line; /* breaks up the text on spaces before hiding */
}
</style>
<div class='text'>some really really really long text</div>
In the CSS for the Div Element, you could use
overflow: hidden
you can use from this text-overflow: ellipsis; of css, check this

Categories

Resources