I am making a text editor, and here is the code:-
const editor = document.querySelector('#ta');
const lc = document.querySelector('#line-count');
var lcDiv = document.createElement('p');
var calculateContentHeight = function( ta, scanAmount ) {
var origHeight = ta.style.height,
height = ta.offsetHeight,
scrollHeight = ta.scrollHeight,
overflow = ta.style.overflow;
/// only bother if the ta is bigger than content
if ( height >= scrollHeight ) {
/// check that our browser supports changing dimension
/// calculations mid-way through a function call...
ta.style.height = (height + scanAmount) + 'px';
/// because the scrollbar can cause calculation problems
ta.style.overflow = 'hidden';
/// by checking that scrollHeight has updated
if ( scrollHeight < ta.scrollHeight ) {
/// now try and scan the ta's height downwards
/// until scrollHeight becomes larger than height
while (ta.offsetHeight >= ta.scrollHeight) {
ta.style.height = (height -= scanAmount)+'px';
}
/// be more specific to get the exact height
while (ta.offsetHeight < ta.scrollHeight) {
ta.style.height = (height++)+'px';
}
/// reset the ta back to it's original height
ta.style.height = origHeight;
/// put the overflow back
ta.style.overflow = overflow;
return height;
}
} else {
return scrollHeight;
}
}
var calculateHeight = function() {
var ta = document.getElementById("ta"),
style = (window.getComputedStyle) ?
window.getComputedStyle(ta) : ta.currentStyle,
// This will get the line-height only if it is set in the css,
// otherwise it's "normal"
taLineHeight = parseInt(style.lineHeight, 10),
// Get the scroll height of the textarea
taHeight = calculateContentHeight(ta, taLineHeight),
// calculate the number of lines
numberOfLines = Math.ceil(taHeight / taLineHeight);
for(let i = 1; i < numberOfLines; i++){
lcDiv = document.createElement('p');
lcDiv.id = 'lcDiv';
lcDiv.innerHTML = i;
lc.appendChild(lcDiv);
}
};
calculateHeight();
if (ta.addEventListener) {
ta.addEventListener("mouseup", calculateHeight, false);
ta.addEventListener("keyup", calculateHeight, false);
} else if (ta.attachEvent) { // IE
ta.attachEvent("onmouseup", calculateHeight);
ta.attachEvent("onkeyup", calculateHeight);
}
#ta{
resize: none;
width: 95%;
line-height: 5vh;
height: 90vh;
background-color :#4C5760;
color: #EFD09E;
font-size: 5vh;
float: left;
}
#line-count{
float: left;
}
<div id="line-count"></div>
<textarea id="ta"></textarea>
I had expected that it will add line numbers when a new line is formed. But it seems that it is not going beyond 1 and the process repeats when I add letters. Can anyone fix this problem.
I expect that it'll show line numbers in a usual way like text editors like Atom, Visual Studio Code, etc.
Help and answers accepted.
You need to clear your #line-count every time you call the calculateHeight()
const editor = document.querySelector('#ta');
const lc = document.querySelector('#line-count');
var lcDiv = document.createElement('div');
var calculateContentHeight = function(ta, scanAmount) {
var origHeight = ta.style.height,
height = ta.offsetHeight,
scrollHeight = ta.scrollHeight,
overflow = ta.style.overflow;
/// only bother if the ta is bigger than content
if (height >= scrollHeight) {
/// check that our browser supports changing dimension
/// calculations mid-way through a function call...
ta.style.height = (height + scanAmount) + 'px';
/// because the scrollbar can cause calculation problems
ta.style.overflow = 'hidden';
/// by checking that scrollHeight has updated
if (scrollHeight < ta.scrollHeight) {
/// now try and scan the ta's height downwards
/// until scrollHeight becomes larger than height
while (ta.offsetHeight >= ta.scrollHeight) {
ta.style.height = (height -= scanAmount) + 'px';
}
/// be more specific to get the exact height
while (ta.offsetHeight < ta.scrollHeight) {
ta.style.height = (height++) + 'px';
}
/// reset the ta back to it's original height
ta.style.height = origHeight;
/// put the overflow back
ta.style.overflow = overflow;
return height;
}
} else {
return scrollHeight;
}
}
var calculateHeight = function() {
var ta = document.getElementById("ta"),
style = (window.getComputedStyle) ?
window.getComputedStyle(ta) : ta.currentStyle,
// This will get the line-height only if it is set in the css,
// otherwise it's "normal"
taLineHeight = parseInt(style.lineHeight, 10),
// Get the scroll height of the textarea
taHeight = calculateContentHeight(ta, taLineHeight),
// calculate the number of lines
numberOfLines = Math.ceil(taHeight / taLineHeight);
lc.innerHTML = "";
for (let i = 1; i < numberOfLines; i++) {
lcDiv = document.createElement('p');
lcDiv.id = 'lcDiv';
lcDiv.innerHTML = i;
lc.appendChild(lcDiv);
}
};
calculateHeight();
if (ta.addEventListener) {
ta.addEventListener("mouseup", calculateHeight, false);
ta.addEventListener("keyup", calculateHeight, false);
} else if (ta.attachEvent) { // IE
ta.attachEvent("onmouseup", calculateHeight);
ta.attachEvent("onkeyup", calculateHeight);
}
#ta {
resize: none;
width: 95%;
line-height: 5vh;
height: 90vh;
background-color: #4C5760;
color: #EFD09E;
font-size: 5vh;
float: left;
}
#line-count {
float: left;
}
#line-count p {
margin: 0;
font-size: 5vh;
}
<div id="line-count"></div>
<textarea id="ta"></textarea>
Related
How can this script start counting from zero? At the moment it starts with the number it's supposed to count to before starting from zero
The JavaScript function loads the counter when it is called into view. How can the numerical values in the counter start with zeros when it is called into view
function isVisible(el) {
const element = $(el);
var WindowTop = $(window).scrollTop();
var WindowBottom = WindowTop + $(window).height();
var ElementTop = element.offset().top;
//var ElementBottom = ElementTop + element.height();
var ElementBottom = ElementTop + 20;
return ElementBottom <= WindowBottom && ElementTop >= WindowTop;
}
function Counter(el) {
obj = $(el);
if (obj.hasClass("ms-animated")) {
return;
}
obj.addClass("ms-animated");
// get the number
var number = obj.text();
obj.attr("data-number", number);
// clear the HTML element
obj.empty();
// create an array from the text, prepare to identify which characters in the string are numbers
var numChars = number.split("");
var numArray = [];
var setOfNumbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// for each number, create the animation elements
for (var i = 0; i < numChars.length; i++) {
if ($.inArray(parseInt(numChars[i], 10), setOfNumbers) != -1) {
obj.append(
'<span class="digit-con"><span class="digit' +
numArray.length +
'">0<br>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br></span></span>'
);
numArray[numArray.length] = parseInt(numChars[i], 10);
} else {
obj.append("<span>" + numChars[i] + "</span>");
}
}
// determine the height of each number for the animation
var increment = obj.find(".digit-con").outerHeight();
var speed = 2000;
// animate each number
for (var i = 0; i < numArray.length; i++) {
obj
.find(".digit" + i)
.animate({
top: -(increment * numArray[i])
},
Math.round(speed / (1 + i * 0.333))
);
}
}
$(window).scroll(function() {
const counterNumbers = $(".number").toArray();
counterNumbers.filter(isVisible).map(Counter);
});
$(window).trigger("scroll");
.number {
display: block;
font-size: 6rem;
line-height: 6.5rem;
}
.number *+* {
margin-top: 0;
}
.digit-con {
display: inline-block;
height: 6.5rem;
overflow: hidden;
vertical-align: top;
}
.digit-con span {
display: block;
font-size: 6rem;
line-height: 6.5rem;
position: relative;
text-align: center;
top: 0;
width: 0.55em;
}
.month {
height: 100vh;
}
<h1>Scroll</h1>
<div class="number">$2,350,354.43</div>
<div class="month">March</div>
<div class="number">$6,350,354.43</div>
<div class="month">March</div>
<div class="number">$8,500,435.33</div>
<div class="month">April</div>
<div class="number">$3,500,435.53</div>
<div class="month">May</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>
Your issue is a something similar to FOUC - Flash of Unstyled Content - where what's originally in the HTML is displayed before it can be updated.
This can be fixed by changing the html and showing the value you want to display on load, while storing the required number in a data- attribute, eg:
<div class="number" data-number="$2,350,354.43">$0,000,000.00</div>
with a small change to your existing code to read the data- instead of text, from
var number = obj.text();
obj.attr("data-number", number); // this is never used
to
var number = obj.data("number");
If you can't change the html (or don't want to) then you can have an initialisation script run before your first scroll initialisation:
$(".number").each((i,e) => {
var obj = $(e);
var number = obj.text();
obj.data("number", number);
obj.text(number.replace(/\d/g, "0"));
});
You will still get FOUC on the very first counter if it's already visible because that's how javascript works: to keep things simple/basic: the page is rendered, then js runs. So there's a short time before the js runs where it's parsing/processing the js ready to run - how long this will be depends on how much js you have (including libraries) / whether it's cached / how much initialisation code there is.
Generally better to output your HTML as you want it displayed rather than rely on JS to update it, but that's not always possible.
Updated snippet:
function isVisible(el) {
const element = $(el);
var WindowTop = $(window).scrollTop();
var WindowBottom = WindowTop + $(window).height();
var ElementTop = element.offset().top;
//var ElementBottom = ElementTop + element.height();
var ElementBottom = ElementTop + 20;
return ElementBottom <= WindowBottom && ElementTop >= WindowTop;
}
function Counter(el) {
obj = $(el);
if (obj.hasClass("ms-animated")) {
return;
}
obj.addClass("ms-animated");
// get the number
//var number = obj.text();
//obj.attr("data-number", number);
var number = obj.data("number");
// clear the HTML element
obj.empty();
// create an array from the text, prepare to identify which characters in the string are numbers
var numChars = number.split("");
var numArray = [];
var setOfNumbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// for each number, create the animation elements
for (var i = 0; i < numChars.length; i++) {
if ($.inArray(parseInt(numChars[i], 10), setOfNumbers) != -1) {
obj.append(
'<span class="digit-con"><span class="digit' +
numArray.length +
'">0<br>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br></span></span>'
);
numArray[numArray.length] = parseInt(numChars[i], 10);
} else {
obj.append("<span>" + numChars[i] + "</span>");
}
}
// determine the height of each number for the animation
var increment = obj.find(".digit-con").outerHeight();
var speed = 2000;
// animate each number
for (var i = 0; i < numArray.length; i++) {
obj
.find(".digit" + i)
.animate({
top: -(increment * numArray[i])
},
Math.round(speed / (1 + i * 0.333))
);
}
}
$(window).scroll(function() {
const counterNumbers = $(".number").toArray();
counterNumbers.filter(isVisible).map(Counter);
});
$(".number").each((i,e) => {
var obj = $(e);
var number = obj.text();
obj.data("number", number);
obj.text(number.replace(/\d/g, "0"));
});
$(window).trigger("scroll");
.number {
display: block;
font-size: 6rem;
line-height: 6.5rem;
}
.number *+* {
margin-top: 0;
}
.digit-con {
display: inline-block;
height: 6.5rem;
overflow: hidden;
vertical-align: top;
}
.digit-con span {
display: block;
font-size: 6rem;
line-height: 6.5rem;
position: relative;
text-align: center;
top: 0;
width: 0.55em;
}
.month {
height: 100vh;
}
<h1>Scroll</h1>
<div class="number">$2,350,354.43</div>
<div class="month">March</div>
<div class="number">$6,350,354.43</div>
<div class="month">March</div>
<div class="number">$8,500,435.33</div>
<div class="month">April</div>
<div class="number">$3,500,435.53</div>
<div class="month">May</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>
I have this little block that I move around using javascript code. It works all good except if I keep moving it, it can easily get out of the box where it is supposed to be.
Can I prevent this somehow? So no matter how far I want to move it, it will stay stuck inside of the container/box ?
Here's my snippet code:
/// store key codes and currently pressed ones
var keys = {};
keys.UP = 38;
keys.LEFT = 37;
keys.RIGHT = 39;
keys.DOWN = 40;
/// store reference to character's position and element
var character = {
x: 100,
y: 100,
speedMultiplier: 2,
element: document.getElementById("character")
};
var is_colliding = function(div1, div2) {
var d1_height = div1.offsetHeight;
var d1_width = div1.offsetWidth;
var d1_distance_from_top = div1.offsetTop + d1_height;
var d1_distance_from_left = div1.offsetLeft + d1_width;
var d2_height = div2.offsetHeight;
var d2_width = div2.offsetWidth;
var d2_distance_from_top = div2.offsetTop + d2_height;
var d2_distance_from_left = div2.offsetLeft + d2_width;
var not_colliding =
d1_distance_from_top <= div2.offsetTop ||
div1.offsetTop >= d2_distance_from_top ||
d1_distance_from_left <= div2.offsetTop ||
div1.offsetLeft >= d2_distance_from_left;
return !not_colliding;
};
/// key detection (better to use addEventListener, but this will do)
document.body.onkeyup =
document.body.onkeydown = function(e){
if (e.preventDefault) {
e.preventDefault();
}
else {
e.returnValue = false;
}
var kc = e.keyCode || e.which;
keys[kc] = e.type == 'keydown';
};
/// character movement update
var moveCharacter = function(dx, dy){
character.x += (dx||0) * character.speedMultiplier;
character.y += (dy||0) * character.speedMultiplier;
character.element.style.left = character.x + 'px';
character.element.style.top = character.y + 'px';
};
/// character control
var detectCharacterMovement = function(){
if ( keys[keys.LEFT] ) {
moveCharacter(-5, 0);
}
if ( keys[keys.RIGHT] ) {
moveCharacter(5, 0);
}
if ( keys[keys.UP] ) {
moveCharacter(0, -5);
}
if ( keys[keys.DOWN] ) {
moveCharacter(0, 5);
}
};
/// update current position on screen
moveCharacter();
/// game loop
setInterval(function(){
detectCharacterMovement();
}, 1000/24);
body{
display: flex;
justify-content: center;
align-items: center;
}
#character {
position: absolute;
width: 42px;
height: 42px;
background: red;
z-index:99;
}
#container{
width: 400px;
height: 400px;
background: transparent;
border:5px solid rgb(0, 0, 0);
position: relative;
overflow: hidden;
}
<div id="container">
<div id="character"></div>
</div>
PS: You can move the box using keyboard arrows.
Get the container width and height into variable and set a condition on your move
var moveCharacter = function(dx, dy){
let div_width = document.getElementById('container').clientWidth;
let div_height = document.getElementById('container').clientHeight;
if((div_width - character.x) < 50 ){ // 50 = width of character and padding
character.x = div_width - 50;
}
if(character.x < 10){ // Padding
character.x = 11;
}
if((div_height - character.y) < 50 ){
character.y = div_height - 50;
}
if(character.y < 10){
character.y = 11;
}
I want to get something like this, in textarea. I cant change textarea to contentaditable div. How do I get the position of the selected text? I need this to show this pop-up from above
You should be able to easily convert this into angular code.
This is the basics of what you need to do, its not thoroughly tested but it bare minimum works.
const textarea = document.getElementById('text')
const result = document.getElementById('selected')
const tooltip = document.getElementById('tooltip')
const cols = document.getElementById('text').cols;
const width = document.getElementById('text').clientWidth;
const height = window.getComputedStyle(textarea).lineHeight;
textarea.onclick = function getSelection() {
const pos = {
top: textarea.offsetTop,
left: textarea.offsetLeft,
};
result.textContent = `${textarea.selectionStart}, ${textarea.selectionEnd}`;
let selection
if (textarea.selectionStart) {
selection = textarea.selectionStart;
} else if (document.selection) {
textarea.focus();
const r = document.selection.createRange();
if (r == null) {
selection = 0;
}
let re = textarea.createTextRange();
let rc = re.duplicate();
re.moveToBookmark(r.getBookmark());
rc.setEndPoint('EndToStart', re);
selection = rc.text.length;
} else {
selection = 0
}
const row = Math.floor((selection - 1) / cols);
const col = (selection - (row * cols));
const x = Math.floor((col * (width / cols)));
const y = (parseInt(height) * row);
tooltip.innerHTML = "<b>row: " + row + "<br>columns" + col + "<br>width: " + width + "</b>";
tooltip.style.top = `${pos.top+y}px`;
tooltip.style.left = `${pos.left+x+10}px`;
}
textarea {
height: 80px;
line-height: 12px;
overflow-y: scroll;
display: block;
}
#tooltip {
position: absolute;
background:red;
color: white;
}
<textarea id="text">Lopsum</textarea>
<span id="tooltip"></span>
<span id="selected"></span>
The only way I imagine is create a duplicate of the text area (very similar to this SO, (the Owen Kelvin's response) about highligth words in a text area
As we only need the position, we can split the "texarea" and the "background". Futhermore, using the Yurzui response in this another SO we can control when resize the textarea
We can imagine an .html like
<div class="container">
<div
#backdrop
class="backdrop"
[style.width.px]="textWidth"
[style.height.px]="textHeight"
>
<div
class="highlights"
[innerHTML]="sanitizer.bypassSecurityTrustHtml(highlightedText)"
></div>
</div>
</div>
<textarea
#textarea
spellcheck="false"
(resize)="rect = null;"
(select)="applyHighlights(textarea.value)"
(mousedown)="mouseDown()"
(blur)="rect = null"
[ngModel]="textValue"
(ngModelChange)="textValue = $event; applyHighlights(textarea.value)"
(scroll)="handleScroll(); applyHighlights(textarea.value)"
></textarea>
<div
class="tooltip"
*ngIf="rect"
[style.top.px]="rect.y"
[style.left.px]="rect.x"
></div>
See that the "text" is hidden because we has a div container like
.container {
overflow:hidden;
width:0;
height:0;
}
And we make that the dimensions of "text" are condition by the two variables "textWidth" and "textHeight"
The code is
ngOnInit() {
this.resize();
}
resize() {
const event = {
width: this.$textarea.nativeElement.getBoundingClientRect().width,
height: this.$textarea.nativeElement.getBoundingClientRect().height,
};
this.textWidth = event.width;
this.textHeight = event.height;
}
mouseDown() {
setTimeout(() => {
const start = this.$textarea.nativeElement.selectionStart;
const end = this.$textarea.nativeElement.selectionEnd;
if (start == end) this.rect = null;
});
}
applyHighlights(text: string) {
if (text) {
let start = this.$textarea.nativeElement.selectionStart;
let end = this.$textarea.nativeElement.selectionEnd;
if (start == end) this.highlightedText = text;
else {
const selected = text.substr(start, end - start);
this.toolTipText=this.getTooltipText(selected)
this.highlightedText =
text.substr(0, start) +
"<span id='mark'>" +
selected +
'</span>' +
text.substr(end);
this.resize();
setTimeout(() => {
const recArea = this.$textarea.nativeElement.getBoundingClientRect();
const recText = this.$backdrop.nativeElement.getBoundingClientRect();
const rect = document.getElementById('mark').getBoundingClientRect();
rect.y += window.scrollY;
rect.x+=rect.width/2
this.rect = rect.y - window.scrollY < recArea.y ? null : rect;
});
}
}
}
handleScroll() {
var scrollTop = this.$textarea.nativeElement.scrollTop;
this.$backdrop.nativeElement.scrollTop = scrollTop;
var scrollLeft = this.$textarea.nativeElement.scrollLeft;
this.$backdrop.nativeElement.scrollLeft = scrollLeft;
}
And in the stackblitz I put in a custom form component (the reason is that Owen make this work for me
Having an issue with changing classes. I can get it to work if I hardcode pixels into the style change but wanted a cleaner version using classes and CSS. The goal is to have the pixel change sizes larger and smaller due to the value of healthPercent in width. This part works but the trouble part is changing the classes to change the color of the bar. For some reason, it does not pass through the if statements correctly and just stays green until death (zero or less for healthPercent), when it reaches zero and then turns red. I can't quite figure out why it passes through the first if check but not the rest. Any ideas on how to fix this?
EDIT: I'm working on a game. just to clarify.
JAVASCRIPT
displayLifeBar = function ()
{
pixelMod = 2.3; //added definition here but global on full code
healthPercent = 130; //added here for example but passed down
lifeBar = 'player_lifebar';
document.getElementById(lifeBar).style.width = healthPercent + 'px';
var criticalLife = 25 * pixelMod;
var lowLife = 50 * pixelMod;
var hurtLife = 75 * pixelMod;
if (healthPercent <= 0){
document.getElementById(lifeBar).className = '';
}
else if (healthPercent < criticalLife){
document.getElementById(lifeBar).className = 'lifebar critical';
}
else if (healthPercent < lowLife){
document.getElementById(lifeBar).className = 'lifebar low';
}
else if (healthPercent < hurtLife){
document.getElementById(lifeBar).className = 'lifebar hurt';
}
else
{
document.getElementById(lifeBar).className = 'lifebar';
}
}
CSS
/* LIFEBAR COLORS STARTS */
.lifebar{
height:20px;
background-color: forestgreen;
}
.lifebar.hurt{
background-color: gold;
}
.lifebar.low{
background-color: orange;
}
.lifebar.critical{
background-color: red;
}
/* LIFEBAR COLORS ENDS */
Your code snippet seems to be working from what you described - assuming your HTML just looks like <div id='player_lifebar'></div>.
var pixelMod = 2.3;
var healthPercent = 10;
var lifeBar = 'player_lifebar';
displayLifeBar = function ()
{
document.getElementById(lifeBar).style.width = healthPercent + 'px';
var criticalLife = 25 * pixelMod;
var lowLife = 50 * pixelMod;
var hurtLife = 75 * pixelMod;
if (healthPercent <= 0){
document.getElementById(lifeBar).className = '';
} else if (healthPercent < criticalLife){
document.getElementById(lifeBar).className = 'lifebar critical';
} else if (healthPercent < lowLife){
document.getElementById(lifeBar).className = 'lifebar low';
} else if (healthPercent < hurtLife){
document.getElementById(lifeBar).className = 'lifebar hurt';
} else {
document.getElementById(lifeBar).className = 'lifebar';
}
}
displayLifeBar();
// for testing:
function modifyHealth(points) {
healthPercent = healthPercent + points;
displayLifeBar(); //re-render healthbar
}
document.getElementById('heal').addEventListener('click', function() { modifyHealth(10) });
document.getElementById('attack').addEventListener('click', function() { modifyHealth(-10) });
.lifebar{
height:20px;
background-color: forestgreen;
}
.lifebar.hurt{
background-color: gold;
}
.lifebar.low{
background-color: orange;
}
.lifebar.critical{
background-color: red;
}
<div id='player_lifebar'></div>
<!-- for testing -->
<br>
<button id='heal'>♡ heal (+10)</button>
<button id='attack'>🗡 attack (-10)</button>
EDIT: Ok, so I approached the problem the wrong way: to do what I intended to, I just needed to check if there was an overflow.
Here is the code (if it can help anyone):
<script type="text/javascript">
function textfit(){
var spans = document.body.getElementsByTagName("span");
for(var i = 0, l = spans.length; i < l; i++){
var span = spans[i];
var font = window.getComputedStyle(span, null).getPropertyValue('font-size');
var fontSize = parseInt(font);
do {
span.style.fontSize = (fontSize --) + "px";
} while (span.scrollHeight > span.clientHeight || span.scrollWidth > span.clientWidth);
}
}
$(document).ready(function() {
textfit();
});
</script>
OLD POST:
My problem is simple: I have a HTML page with a lot of span but not all of them have the same content. Regarding that, I want to adapt the fontsize of each content to fit perfectly its span; please note that I don't want to cut the textcontent, or add dots if it's too long, I just want to modify the fontSize.
JS:
function = textfit(){
var spans = document.body.getElementsByTagName("span");
for(var i = 0, l = spans.length; i < l; i++){
var maxHeight = spans[i].offsetHeight;
var maxWidth = spans[i].offsetWidth;
var textHeight = $(spans[i].textContent).height();
var textWidth = $(spans[i].textContent).width();
var fontSize = spans[i].style.fontSize;
do {
fontSize = fontSize - 1;
} while (textHeight > maxHeight || textWidth > maxWidth);
}
}
$(document).ready(function() {
textfit();
});
HTML/CSS:
<style>
span{
display: inline-block;
width: 100px;
height: 100px;
font-size: 20pt;
}
</style>
......
<body>
<div>
<span>SMALL</span>
<span>MEEEEEEEEEEEEEDIUM</span>
<span>HUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUGE</span>
</div>
</body>
As you may see, I'm using a "for" to run through every span and a "do...while" to adjust the font size of each of them.
My problems:
it looks like I'm not able to get the textcontent size (getting a "null" instead)
same thing with the fontsize (I'm getting an empty string)
Or maybe I'm approaching the problem the wrong way and I need to do it differently...
NB: JS are a little bit "new" for me so sorry if I did rookie mistakes
you are reseting a local variable by fontSize = fontSize - 1;, on a related note, textHeight and textWidth will not be update automatically by changing the fontsize, they are local variables.
On the other hand, you will need to wrap your texts in an additional element to be able to measure its dimensions.
<style>
.wrapper{
display: inline-block;
width: 100px;
height: 100px;
font-size: 20pt;
}
</style>
......
<body>
<div>
<span class='wrapper'><span>SMALL</span></span>
<span class='wrapper'><span>MEEEEEEEEEEEEEDIUM</span></span>
<span class='wrapper'><span>HUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUGE</span></span>
</div>
</body>
JS:
function = textfit(){
var spans = document.body.getElementsByClassName("wrapper");
for(var i = 0, l = spans.length; i < l; i++){
var span = spans[i];
var maxHeight = span.offsetHeight;
var maxWidth = span.offsetWidth;
var fontSize = parseInt(span.style.fontSize);
do {
var textHeight = span.firstChild.offsetHeight();
var textWidth = span.firstChild.offsetWidth();
span.style.fontSize = (fontSize --)+"pt";
} while (textHeight > maxHeight || textWidth > maxWidth);
//PS I suggest a binary-search-like algorithm to save time
}
}
$(document).ready(function() {
textfit();
});