I'm trying to dynamicly resize text within a div so that the text does not run outside of the box it was intended for. I'm trying to do this so that I can make a printable form.
Geeky Monkey has a jquery plugin that works great but my problem is I can't loop it to do it over and over for different div's to make sure they're all properly sized. If I make all my div's the same class they all get the same text size so obviously this doesn't work.
This is Geeky Monkey's unedited code
(function($) {
$.fn.textfill = function(options) {
var fontSize = options.maxFontPixels;
var ourText = $('span:visible:first', this);
var maxHeight = $(this).height();
var maxWidth = $(this).width();
var textHeight;
var textWidth;
do {
ourText.css('font-size', fontSize);
textHeight = ourText.height();
textWidth = ourText.width();
fontSize = fontSize - 1;
} while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
return this;
}
})(jQuery);
$(document).ready(function() {
$('.jtextfill').textfill({ maxFontPixels: 36 });
});
And the html code that goes with it
<div class='jtextfill' style='width:100px;height:50px;'>
<span>My Text Here</span>
</div>
This is what I tried to do to change it and make it a loop
$(document).ready(
for(i=1;i<3;i++){
function() {
$('.jtextfill' + i).textfill({ maxFontPixels: 72 });
})};
And the html to go with my revision
<div class='jtextfill1' style='width:400px;height:200px;'>
<span>THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG</span>
</div>
<div class='jtextfill2' style='width:50px;height:25px;'>
<span>THIS IS THE SECOND PART OF MY TEXT</span>
</div>
As I'm sure you could guess it's not working. jquery does still confuse me so please forgive me if it is an obvious mistake. Any help would be greatly appreciated.
Thanks
OK, as I understand it you want to have various divs each with a different class so that you can give each its own font size (and potentially other individual properties). You want to be able to process each div to - if necessary - shrink the font of the span in the div so that it will fit in the div without overflowing.
If so, calling the textfill() method in a loop but passing the same maxFontPixels parameter to it for every div won't work, because obviously they'll all then start out with the same default maximum font size. You could update your loop to pass in different font sizes, but instead I would suggest changing the textfill() to start with the current font-size of the div, rather than taking it as a parameter.
Then, rather than trying to do a loop to repeatedly call textfill(), you can use a single JQuery selector that selects all of the divs you want to process. Following is just one way to do what I've described. (Note: I haven't actually tested it, but I hope it will get you on your way.)
EDIT: In the original code there was also a basic problem with the .textfill plugin, that (as with any JQuery plugin) its this was a JQuery object that - depending on the selector - may be a list of many DOM elements, but it was treating it as a single DOM element. Just needed to add a this.each() loop around the rest of the function code and it works.
<style>
.someclass1 { font-size: 36px; }
.someclass2 { font-size: 48px; }
</style>
<div class='someclass1 jtextfill' style='width:400px;height:200px;overflow:hidden;'>
<span>THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG</span>
</div>
<div class='someclass2 jtextfill' style='width:50px;height:25px;overflow:hidden;'>
<span>THIS IS THE SECOND PART OF MY TEXT</span>
</div>
<script>
(function($) {
$.fn.textfill = function() {
// EDIT: added the .each()
this.each(function() {
var fontSize = parseInt($(this).css('font-size'),10);
var ourText = $('span:visible:first', this);
var maxHeight = $(this).height();
var maxWidth = $(this).width();
var textHeight;
var textWidth;
do {
ourText.css('font-size', fontSize + "px");
textHeight = ourText.height();
textWidth = ourText.width();
fontSize = fontSize - 1;
} while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
// EDIT: added the closing brackets for the .each
});
return this;
}
})(jQuery);
$(document).ready(function() {
$('.jtextfill').textfill();
});
</script>
Notes: in this case the 'jtextfill' class isn't actually defined in the stylesheet, it is used solely as a convenient way to let JQuery select all of the divs that you want to process. The actual font stylings are applied via the 'someClass1', etc., classes. (In case you weren't aware, HTML/CSS allows you to apply multiple classes to the same element.)
I've changed only twothree things in the textfill() method: (1) I get the font-size from the element, which should be returned as a string like '36px', then use parseInt to grab the integer part of that (throwing away the 'px'). (2) When the font is set inside the loop I append 'px' back onto the font size. (3) Added a .each() loop within the plugin function.
Related
I want to resize the textarea to fit the contents of the text area.
I am currently using the following code to do that:
var element = document.getElementById(event.target.id);
var content = $(this).val().trim();
if (content == "") {
$(this).animate({
width: element.scrollWidth,
height: element.scrollHeight
}, 100);
}
When I enter nothing. I expect the textarea to become smaller in size and eventually disappear.
But it is expanding instead. :(
JSFiddle: http://jsfiddle.net/7vfjet1g/
I think what you're looking for is an elastic text area. There are a few JavaScript libraries that provide this functionality:
https://github.com/chemerisuk/better-elastic-textarea
https://github.com/chrisgeo/elastic-textarea
http://unwrongest.com/projects/elastic/
It's not much code, but a careful combination of JavaScript and CSS. If for some reason you don't want to add another library to your project, or this doesn't fit your requirement, it may point you in the right direction. Good luck.
I tested out your existing code, and the values that scrollWidth and scrollHeight were giving you were much bigger than the size of the actual text.
One way to get the size of the actual text is to create a span with the same font styling as the text area, copy over the value of the textarea to it, then append the span to the document. You can then use getBoundingRect() to get the dimensions of the span, and thus the dimensions of the text in your textarea.
NOTE: I changed the id of your enclosing div. It had the same id as the textarea, and ids are supposed to be unique. Having two elements with the same id could cause problems with the javascript. Here's the jsfiddle: https://jsfiddle.net/yog8kvx7/7/. And here's the updated blur function:
$('.notesArea').blur(function (event)
{
var content = $(this).val().trim();
var element = document.getElementById(event.target.id);
// Create span to calculate width of text
var span = document.createElement('span');
// Set position to absolute and make it hidden
// so it doesn't affect the position of any other elements
span.style.position = 'absolute';
span.style.visibility = 'hidden';
// Only set to whitespace to pre if there's content
// "pre" preserves whitespace, including newlines
if (element.value.length > 0)
span.style.whiteSpace = 'pre-wrap';
// Copy over font styling
var fontStyle = window.getComputedStyle(element);
span.style.display = 'inline-block';
span.style.padding = fontStyle.padding;
span.style.fontFamily = fontStyle.fontFamily;
span.style.fontSize = fontStyle.fontSize;
span.style.fontWeight = fontStyle.fontWeight;
span.style.lineHeight = fontStyle.lineHeight;
span.innerHTML = element.value;
// Add to document and determine width
document.body.appendChild(span);
var rect = span.getBoundingClientRect();
var width = rect.width;
var height = rect.height;
// Remove span from document
span.parentNode.removeChild(span);
$(this).animate({
width: width,
height: height
}, 100);
});
And if you want to account for the little sizing handle, so it doesn't cover the text, you can just add an offset to the width to account for it.
I have a div with a static size. Sometimes longer text than the div will be placed there. Is there anyway to achieve the text fitting the div width at all times through JavaScript alone? I am aware there are jQuery fixes but need a pure JS solution in this case.
Even if you have a link to a demo/tutorial that would be helpful, thanks.
Here you go, this should do what you want: JSFiddle
Basically the key here is to check the output.scrollHeight against output.height. Consider the following setup:
HTML:
<button onclick="addText(); resizeFont()">Click Me to Add Some Text!</button>
<div id="output"></div>
CSS:
div {
width: 160px;
height: 160px;
}
This creates a square div and fills it with a randomly long string of text via the addText() method.
function addText() {
var text = "Lorem ipsum dolor amit",
len = Math.floor(Math.random() * 15),
output = document.querySelector('#output'),
str = [];
for (; --len;)
str.push(text);
output.innerHTML = str.join(', ');
}
The magic lies in the resizeFont() function. Basically what this does is, once the text has been added, it sets the fontSize of the div to be equal to its own height. This is the base case for when you have a string of 1 character (i.e. the fontSize will equal the height). As the length of your string grows, the fontSize will need to be made smaller until the scrollHeight equals the height of the div
function resizeFont() {
var output = document.querySelector('#output'),
numRE = /(\d+)px/,
height = numRE.exec(window.getComputedStyle(output).height)[1],
fontSize = height;
// allow div to be empty without entering infinite loop
if (!output.innerHTML.length) return;
// set the initial font size to the height of the div
output.style.fontSize = fontSize + 'px';
// decrease the font size until the scrollHeight == height
while (output.scrollHeight > height)
output.style.fontSize = --fontSize + 'px';
}
The nice thing about this method is that you can easily attach an event listener to the resize event of the window, making the text dynamically resize as the user changes the window size: http://jsfiddle.net/QvDy8/2/
window.onload = function() {
window.addEventListener('resize', resizeFont, false);
}
On the right side of my page I have a list of sponsors.
My active page area (left side) height varies from page to page, depending on the story it contains every time.
I want the list's height to match the live pages height, so I thought I'd always show the main sponsors, and for the rest of them, I'd hide them, and show exactly as many as I can each time.
My markup looks like this:
<div id="xorigoi">
<a class="basic"><img src="/views/images/adjustable/sideXorigoi/1.png"></a>
<a class="basic"><img src="/views/images/adjustable/sideXorigoi/2.png"></a>
<a class="basic"><img src="/views/images/adjustable/sideXorigoi/3.png"></a>
<a class="rest"><img src="/views/images/adjustable/sideXorigoi/4.png"></a>
<a class="rest"><img src="/views/images/adjustable/sideXorigoi/5.png"></a>
<a class="rest"><img src="/views/images/adjustable/sideXorigoi/6.png"></a>
<a class="rest"><img src="/views/images/adjustable/sideXorigoi/7.png"></a>
<a class="rest"><img src="/views/images/adjustable/sideXorigoi/8.png"></a>
</div>
Every image is a link to each sponsor's site. Every image has it's own height.
Elements that have the class .rest are hidden using display: none
I'm trying to calculate if adding the new image will make the list longer than the page, but since the elements are hidden, offsetHeight = 0.
What can I do?
My javascript/jquery code so far looks like this:
$(
function(){
var containerHeight = $('#mainPageContainer')[0].offsetHeight; // total height of page
var xorigoi = $('#mainRightSide .rest'); // select the sponsors
var newHeight = 1062; // this is the right side height I am already using
$.each( xorigoi , function( index ){
if( newHeight + heightOfNewElement > containerHeight ){
return false; // break each
}
xorigoi.eq(index).css('display','block'); // display the sponsor
newHeight = newHeight + heightOfNewElement;
})
}
)
So bottomline, how can I get heightOfNewElement in the function above?
Since JavaScript is single-threaded, the browser will not redraw while it is executing. As such, you can safely set the elements to display:block, measure them, then hide them again and the user will be none the wiser.
Instead of display none, you could consider moving your elements outside the viewport. For example:
.rest {position:absolute;top:-9999px;}
Guess this will help you.
console.log(getDimensions($('#myElement')));
function getDimensions(element){
var tempElement = $(element).clone();
$(tempElement).css('display','block').css('visibility','hidden');
$(document.body).append(tempElement);
var obj = new Object();
obj.width = $(tempElement).width();
obj.height = $(tempElement).height();
$(tempElement).remove();
return obj;
}
This question already has answers here:
Font scaling based on size of container
(41 answers)
Closed 1 year ago.
I have a container that has a % width and height, so it scales depending on external factors. I would like the font inside the container to be a constant size relative to the size of containers. Is there any good way to do this using CSS? The font-size: x% would only scale the font according to the original font size (which would be 100%).
If you want to set the font-size as a percentage of the viewport width, use the vwunit:
#mydiv { font-size: 5vw; }
The other alternative is to use SVG embedded in the HTML. It will just be a few lines. The font-size attribute to the text element will be interpreted as "user units", for instance those the viewport is defined in terms of. So if you define viewport as 0 0 100 100, then a font-size of 1 will be one one-hundredth of the size of the svg element.
And no, there is no way to do this in CSS using calculations. The problem is that percentages used for font-size, including percentages inside a calculation, are interpreted in terms of the inherited font size, not the size of the container. CSS could use a unit called bw (box-width) for this purpose, so you could say div { font-size: 5bw; }, but I've never heard this proposed.
Another js alternative:
Working Example
fontsize = function () {
var fontSize = $("#container").width() * 0.10; // 10% of container width
$("#container h1").css('font-size', fontSize);
};
$(window).resize(fontsize);
$(document).ready(fontsize);
Or as stated in torazaburo's answer you could use svg. I put together a simple example as a proof of concept:
SVG Example
<div id="container">
<svg width="100%" height="100%" viewBox="0 0 13 15">
<text x="0" y="13">X</text>
</svg>
</div>
You may be able to do this with CSS3 using calculations, however it would most likely be safer to use JavaScript.
Here is an example: http://jsfiddle.net/8TrTU/
Using JS you can change the height of the text, then simply bind this same calculation to a resize event, during resize so it scales while the user is making adjustments, or however you are allowing resizing of your elements.
I used Fittext on some of my projects and it looks like a good solution to a problem like this.
FitText makes font-sizes flexible. Use this plugin on your fluid or responsive layout to achieve scalable headlines that fill the width of a parent element.
It cannot be accomplished with css font-size
Assuming that "external factors" you are referring to could be picked up by media queries, you could use them - adjustments will likely have to be limited to a set of predefined sizes.
Here is the function:
document.body.setScaledFont = function(f) {
var s = this.offsetWidth, fs = s * f;
this.style.fontSize = fs + '%';
return this
};
Then convert all your documents child element font sizes to em's or %.
Then add something like this to your code to set the base font size.
document.body.setScaledFont(0.35);
window.onresize = function() {
document.body.setScaledFont(0.35);
}
http://jsfiddle.net/0tpvccjt/
I had a similar issue but I had to consider other issues that #apaul34208 example did not tackle. In my case;
I have a container that changed size depending on the viewport using media queries
Text inside is dynamically generated
I want to scale up as well as down
Not the most elegant of examples but it does the trick for me. Consider using throttling the window resize (https://lodash.com/)
var TextFit = function(){
var container = $('.container');
container.each(function(){
var container_width = $(this).width(),
width_offset = parseInt($(this).data('width-offset')),
font_container = $(this).find('.font-container');
if ( width_offset > 0 ) {
container_width -= width_offset;
}
font_container.each(function(){
var font_container_width = $(this).width(),
font_size = parseFloat( $(this).css('font-size') );
var diff = Math.max(container_width, font_container_width) - Math.min(container_width, font_container_width);
var diff_percentage = Math.round( ( diff / Math.max(container_width, font_container_width) ) * 100 );
if (diff_percentage !== 0){
if ( container_width > font_container_width ) {
new_font_size = font_size + Math.round( ( font_size / 100 ) * diff_percentage );
} else if ( container_width < font_container_width ) {
new_font_size = font_size - Math.round( ( font_size / 100 ) * diff_percentage );
}
}
$(this).css('font-size', new_font_size + 'px');
});
});
}
$(function(){
TextFit();
$(window).resize(function(){
TextFit();
});
});
.container {
width:341px;
height:341px;
background-color:#000;
padding:20px;
}
.font-container {
font-size:131px;
text-align:center;
color:#fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container" data-width-offset="10">
<span class="font-container">£5000</span>
</div>
https://jsfiddle.net/Merch80/b8hoctfb/7/
I've given a more detailed answer of using vw with respect to specific container sizing in this answer, so I won't just repeat my answer here.
In summary, however, it is essentially a matter of factoring (or controlling) what the container size is going to be with respect to viewport, and then working out the proper vw sizing based on that for the container, taking mind of what needs to happen if something is dynamically resized.
So if you wanted a 5vw size at a container at 100% of the viewport width, then one at 75% of the viewport width you would probably want to be (5vw * .75) = 3.75vw.
If you want to scale it depending on the element width, you can use this web component:
https://github.com/pomber/full-width-text
Check the demo here:
https://pomber.github.io/full-width-text/
The usage is like this:
<full-width-text>Lorem Ipsum</full-width-text>
You can also try this pure CSS method:
font-size: calc(100% - 0.3em);
I am implementing a jquery file upload page. While a user is adding files, I want them to be getting listed in a form of an icons in an auto-sizable grid.
Auto-sizable means it provides maximum space for containing elements. When there is two objects - it woud look like (I know i will have to handle image resizing myself):
When several are added:
Is there a "grid control" (jquery perhaps) that does at least close to what I need sizing wise?
First of all, please keep in mind that I'm a jQuery newbie and this is my first post on Stackoverflow :)
I've the same problem and I've try to fix it using jQuery and CSS. This is my body tag content:
<div id="controls">
Controls:
<button id="add">+</button>
<button id="del">-</button>
Current ratio:
<span id="value"></span>
<button id="increase">+</button>
<button id="decrease">-</button>
Referred to:
<form style="display: inline;">
width<input type="radio" name="maximize" value="width">
height<input type="radio" name="maximize" value="height">
</form>
</div>
<div id="elements" style="width: 500px; height: 300px; background: black;">
</div>
<script>
ratio = 1;
ratioWidth = true;
function autoresize() {
boxes = $('#elements').children().size();
rows = Math.ceil(Math.sqrt(boxes/ratio));
columns = Math.ceil(boxes/rows);
if (!ratioWidth) {
tmp = rows;
rows = columns;
columns = tmp;
}
$('#elements').children().css('width', 100/rows+'%');
$('#elements').children().css('height', 100/columns+'%');
}
function add() {
red = Math.floor(Math.random()*256);
green = Math.floor(Math.random()*256);
blue = Math.floor(Math.random()*256);
color = 'rgb('+red+','+green+','+blue+')';
$('#elements').append("<div style=\"background: "+color+"; float: left;\"></div>");
autoresize();
}
function update() {
$('#value').text(ratio);
autoresize();
}
function remove() {
$('#elements').children().last().remove();
update();
}
function increase() {
ratio++;
update();
}
function decrease() {
if (ratio > 1) {
ratio--;
update();
}
}
$(document).ready(function() {
$('#add').click(add);
$('#del').click(remove);
$('#increase').click(increase);
$('#decrease').click(decrease);
if (ratioWidth) value = 'width'
else value = 'height'
$('input[type=radio]').filter('[value='+value+']').attr('checked', true);
$('input[type=radio]').live('change', function() {
if ($(this).val() == 'width') ratioWidth = true
else ratioWidth = false;
autoresize();
});
update();
//$(window).bind("resize", autoresize);
});
</script>
You could remove the background color stuff and put your icons centered in those boxes.
If you find a better way of if you improve this code, please let me know :)
Edit 1 - I've added some Math.floor(...) to remove a bug when boxes side has repeating decilmals: very size is a simple integer. Now dimensions are fetched from the container div, I use black as background color for the main container and I've noticed a little issue: sometimes I see a black border near the little boxes, even if I don't set any background color. Could it be a Firefox rendering glitch?
Edit 2 - Now it's possible to set if you prefer to auto-expand horizontally, vertically, or none of them. I've tried to write a better code, and I've commented autoresize when the window is resized (use it only if your container box hasn't a fixed height/width). I think that now it needs an ratio option, in order to specify if width have to be twice longer for example. Live example: http://experimental.frafra.eu/maxarea2.html
Edit 3 - New code! Better graphical representation and a new parameter: ratio. Ratio is a coefficient between the ratio between main container width/height and the elements one. Live example: http://experimental.frafra.eu/maxarea3.html