Is there a way to limit the amount of letters that can be put into an inputfield depending on the size it takes up?
For example W's and M's take enough space to place 34 of them.
But if i use normal sentences the same amount of letters is only taking half of the size up in comparison to the W's and M's.
What i want is that i can basically write anything as long the Size of the inputfield is big enough.
Is that possible?
First, you can access to the size of your input with something like this :
const ele = document.getElementById('yourInputId');
const eleStyle = window.getComputedStyle(ele);
const inputSize = {width: eleStyle.width, height: eleStyle.heigth};
Then, in another method, assuming you know the font and font-size of your text (if you don't, check Angular Documentation), you can set-up a method like this :
pixelLength(txt: string, font: number) {
const canva = document.createElement('CANVAS');
const attr = document.createAttribute('id');
attr.value = 'myId';
canva.setAttributeNode(attr);
document.body.appendChild(canva);
const c: any = document.getElementById('myId');
const ctx = c.getContext('2d');
ctx.font = font.toString() + 'px Helvetica';
const result = ctx.measureText(txt).width;
document.body.removeChild(canva);
return result;
}
You might want to call this method in a custom form control, to check if it will be longer than inputSize.width.
Let me know if something's unclear ;)
Happy coding.
Related
I am looking to replace a string within a Google Doc via an app script. The string will exist on a line, but after the replace, I want it to have a specific font, size and justification.
I've created a style to address all these attributes (I included both Horiz. and Vert. alignment) and most of it works fine. When the string is replaced, the replacement has the right font, size and bold attributes. For some reason, I cannot get the justification to get changed.
// Define the style for the replacement string.
var hdrStyle = {};
hdrStyle[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] =
DocumentApp.HorizontalAlignment.CENTER;
hdrStyle[DocumentApp.Attribute.VERTICAL_ALIGNMENT] =
DocumentApp.VerticalAlignment.CENTER;
hdrStyle[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
hdrStyle[DocumentApp.Attribute.FONT_SIZE] = 24;
hdrStyle[DocumentApp.Attribute.BOLD] = true;
{ then later }
documentBody = DocumentApp.openById(fileId).getBody();
hdrElem = documentBody.findText("old string").getElement();
hdrText = hdrElem.asText().setText("new string");
// Force our 'header style':
hdrElem.setAttributes(hdrStyle);
I've tried setting the style after the findText and (as here) after, but no change in centering.
I see there is a paragraph centering, but I am not clear how to 'get' the paragraph associated with the element that is returned on the find.
I'm hoping this is some simple set of calls - but have run out of ideas (and patience)..!
Any help would be appreciated!
You can use getParent() on hdrElem to get the parent paragraph to apply the styling to.
https://developers.google.com/apps-script/reference/document/text#getParent()
documentBody = DocumentApp.openById(fileId).getBody();
hdrElem = documentBody.findText("old string").getElement();
hdrText = hdrElem.asText().setText("new string");
var hdrParent = hdrElem.getParent()
// Force our 'header style':
hdrParent.setAttributes(hdrStyle);
I wonder how to set the text "Highlight" of a part of text inside tlfTextField with the code?
I tried "tf.backgroundColor = 0x990000" property, but did not help.
For instance, I can change the Font Color of any contents inside Parenthesis, by this code:
private function decorate():void {
var tf:TextFormat = new TextFormat();
tf.color = 0x990000;
var startPoint:int = 0;
while (startPoint != -1) {
var n1:int = textMc.tlfText.text.indexOf("(", startPoint);
var n2:int = textMc.tlfText.text.indexOf(")", n1 + 1);
if (n1 == -1 || n2 == -1) {
return;
}
textMc.tlfText.setTextFormat(tf, n1 + 1, n2);
startPoint = n2 + 1;
}
}
So I know "tf.color = 0x990000;" will change the Font color, however, don't know how to "highlight" some text, with code, as I do inside Flash manually.
You should have probably used tlfMarkup property to set the required format to the specific part of text. The attributes you seek are backgroundColor and backgroundAlpha of the span XML element that you should wrap your selection, however it should be much more difficult should there already be spans around words when you retrieve the property from your text field.
The problem with your solution is that you don't check if the two characters are located on a single line before drawing your rectangle, also you would need to redraw such rectangles each time something happens with the textfield. The proposed approach makes use of Flash HTML renderer's capabilities to preserve the formatting, however it will require a lot of work to handle this task properly.
In looking at this image you can see in an ideal world each box would have the same height of content in each box. However in the real world we can't control how many characters the client uses for a heading. Wondering thoughts on how to deal with a situation like this? Is it ok to just let it be as is?
This will create an array of heights of an element by class, then find the tallest, and then make them all that height.
<script>
var headerHeights = [];
var mclength = document.getElementsByClassName("myClass").length;
for (i = 0; i < mclength; i++) {
headerHeights[i] = document.getElementsByClassName("myClass")[i].getBoundingClientRect().height;
}
var headerMaxHeight = Math.max(...headerHeights);
for (i = 0; i < mclength; i++) {
document.getElementsByClassName("myClass")[i].style.height = headerMaxHeight+"px";
}
</script>
You will likely want to make this a function which replaces "myClass" with a function parameter so that you can call it for each class you add. You will also want to add a listener for when a person resizes their window to rerun the function.
I have put together a calculator what calculates a price, depending on user input. It works fine with one input, but now I have to scale it a little with a second user input. But here's the catch: the user might not want to put anything to the field, so it will be empty. And that's the thing that brakes my code. I could duplicate the calculator function and return the values and add those two together in a third function, but it will not work when there's an empty value.
Just for the sake of it, some trivial HTML code:
//When I only calculate with this user input, its easy
<input type="text" id="rocktext"><br>
// But how to consider this and do the same exact calculations like with the
//first one and add those two result together?
<input type="text" id="rocktext2"><br>
The code in the end should look like:
Take first user input, calculate the price(like in code below)
IF(!!) there is a second user input, calculate the price and add it to
the first one
Am I being a moron to try it with JS or just a moron in the firstplace?
Hope to hear from You, guys!
J.
The initial JS code is as follows:
function priceCalc() {
var inputs = document.getElementById("rocktext").value;
var length = inputs.length;
var accept = 6;
var initPrice = 8;
if (inputs<=accept){
// Since the code is much simpler right now i just put the result in HTML as follows:
document.getElementById("rockpricetotal").innerHTML = initPrice + " dollars";
//I can also return the the value calculated here like so:
//retVal = initPrice;
}
else {
var intLength = parseInt(length, 10);
var lengthGap = intLength - accept;
var totals = lengthGap * 0.8 + initPrice;
var prec = totals.toPrecision(3);
// Since the code is much simpler right now i just put the result in HTML as follows:
document.getElementById("rockpricetotal").innerHTML = prec + " dollars";
// Here also the return clause can be possible with the calculation result like so:
//retVal = prec;
}
// And the final return as an alternative to the innerHTML :
// return retVal;
}
Making it scalable, you can add a class to all the inputs which may be in the function (something like calcInput), so you iterate all of them and if the value isn't empty (and if it's a valid number), you put it in the calculation.
Or you can just verify if the second input is empty, if so, calls functionOne, if not, calls functionTwo:
function twoDifferentWays() {
var valueOne = document.querySelector("#rocktext").value;
var valueTwo = document.querySelector("#rocktext2").value;
if (!!valueTwo && !isNaN(valueTwo)) {
callsFunctionOne(valueOne, valueTwo);
} else {
callsFunctionTwo(valueOne, valueTwo);
}
}
I have a responsive app for desktop and mobile.
In the app i have a div which randomly shows texts of all kinds of lengths.
I want to do the following:
If the line breaks because the length of the text is too wide for the width of that div, i want the font-size to reduce itself (I am using em's in my app).
Is it something i need to build directive for it? is it something that was built and used wildly?
Writing a robust solution for this problem is going to be non-trivial. As far as I know, there's no way to tell whether a line of text breaks. However, we do know the criteria for line breaking is the width of the text being wider than the element, accounting for padding.
The Canvas API has a method called measureText which can be used to measure a string, using a given context with a font and size set. If you spoof the settings of the element with a canvas, then you can measure the text with the canvas and adjust the size until it fits without overflowing.
I've written up a rough implementation of the way I would tackle this.
function TextScaler(element) {
var canvas = document.createElement('canvas'),
context = canvas.getContext('2d');
var scaler = {};
scaler.copyProps = function() {
var style = element.style.fontStyle,
family = element.style.fontFamily,
size = element.style.fontSize,
weight = element.style.fontWeight,
variant = element.style.fontVariant;
context.font = [style, variant, weight, size, family].join(' ');
};
scaler.measure = function(text) {
text = text || element.innerText;
return context.measureText(text);
};
scaler.overflows = function() {
var style = window.getComputedStyle(element),
paddingLeft = style['padding-left'],
paddingRight = style['padding-right'],
width = style.width - paddingLeft - paddingRight;
return scaler.measure() > width;
};
scaler.decrease = function() {
// decrease font size by however much
};
scaler.auto = function(retries) {
retries = retries || 10;
if(retries <= 0) {
scaler.apply();
console.log('used all retries');
}
if(scaler.overflows()) {
scaler.decrease();
scaler.auto(retries - 1);
} else {
console.log('text fits');
scaler.apply();
}
};
scaler.apply = function() {
// copy the properties from the context
// back to the element
};
return scaler;
}
After you've sorted out some of the blank details there, you'd be able to use the function something like this:
var element = document.getElementById('');
var scaler = TextScaler(element);
scaler.auto();
If it doesn't manage to decrease it within 10 retries, it will stop there. You could also do this manually.
while(scaler.overflows()) {
scaler.decrease();
}
scaler.apply();
You'd probably want some fairly fine tuned logic for handling the decrease function. It might be easiest to convert the ems to pixels, then work purely with integers.
This API could quite trivially be wrapped up as a directive, if you want to use this with Angular. I'd probably tackle this with two attribute directives.
<div text-scale retries="10">Hello world</div>
Of course, if it's not important that all the text is there onscreen, then you can just use the text-overflow: ellipsis CSS property.