Scaling text to fit within FabricJS Textbox when changing text value programmatically - javascript

I am using a FabricJS Textbox in my canvas application to allow users to edit text. This is working fantastically for me, as I want text to wrap during editing, and wrap/unwrap as the width of the box is shrunken and expanded.
However, I have a secondary use case that I need some guidance on.
Occasionally, I need to replace the text in the textbox programmatically. In this scenario, I do not want the textbox to wrap text or expand when the text is too long for the width. Instead, I would like to reduce the fontSize so that the text fits on one line.
Note: I only do this text replacement once when the canvas is loaded (or just before in the JSON).
I currently handle this with IText using the following code, but I cannot seem to modify it in a way that works reliably with Textbox. I also lose out on the fantastic text wrapping if I use IText, which is why I'm evaluating this.
const handleTextChanged = ({ target }: { target: fabric.Object }) => {
const { fixedWidth, width, fontSize } = target
if (width > fixedWidth) {
// Shrink the font size to stay within the max width
target.fontSize = Math.round((fontSize * fixedWidth) / (width + 1))
}
target.width = fixedWidth
}
Is there a way to achieve something like this using just Textbox? That is, I would like to keep text wrapping and unwrapping functionality during normal editing, but I would also like to load text in programmatically and have the font size scale to fit the box when I load the canvas.

const originalWidth = element.width;
element.set({ objectCaching: false, text: data2.value.toString() })
if (element.textLines.length > 1) {
do {
element.set({ width: element.width + 5 });
}
while (element.textLines.length > 1);
element.set({ scaleX: originalWidth / element.width });
}

Related

vuetify v-bind inline style value not updating

I have a tricky layout that I believe can only be responsive with JavaScript, but I can't manage to get inline styling with bound data to accomplish this. There is a wrapper element around an image that I want to be the height of the image plus 80px. For brevity, I'll just post the two elements that I need working together, and cut out the extra markup because it is irrelevant.
<v-flex v-resize="onResize" v-bind:style="{height: this.imageHeight}" xs12 md6>
{{this.imageHeight}}
<img src="../assets/images/image1.jpg" alt="image" ref="desktop-image">
</v-flex>
In data, I define imageHeight as 0 at first with the intention of having that value update once the page loads or the screen is resized.
data () {
return {
imageHeight : 0
}
}
Then in mounted(), I redefine the imageHeight data to be the height I want.
this.imageHeight = this.$refs["desktop-image"].offsetHeight + 80;
I also include this in the resize method.
onResize () {
this.imageHeight = this.$refs["desktop-image"].offsetHeight + 80;
}
Once the page loads or once I resize the screen, the outputted {{this.imageHeight}} value that I have above the image updates correctly, but it never updates in the v-bind:style on the image element so the height stays at 0px.
How can I get the inline styling data to update like it does elsewhere?
The height CSS property must be either:
a <length> value with length units (for non-zero values); e.g., 200px
or:
a <percentage> value; e.g., 100%
A number value is invalid. The value is in the form of a string, so your code should append 'px' to the calculated number:
this.imageHeight = this.$refs["desktop-image"].offsetHeight + 80 + 'px';
demo

How to increase height of textArea dynamically upto 3 line height (Just like whatsApp message box) in titanium appcelerator?

I need to implement dynamic height of textarea that expects a user to type comment. I have seen the interaction of textArea like this on WhatsApp.
The text area will be initially of 1 line height later on as the user enters the text it should increase. But the text area should not be increased more than 3 line height.
As of now, I used a workaround to achieve that.
var _lines = textFieldValue.split(/\r\n|\r|\n/).length;
if(_lines > 3 || textFieldValue.length > 90) {
$.textAreaDescriptionId.height = "80dp";
} else {
$.textAreaDescriptionId.height = Titanium.UI.SIZE;
}
I would use something like this:
$.textArea.height = $.textArea.font.fontSize * 3 // plus some padding
Add a padding because otherwise it will be too small. The fontSize * 3 is the minimum you should have for 3 lines.
Edit
As mentioned in the comments. There is currently no way to set maxLines for a TextField in Titanium. So it won't work dynamically.
Ticket and PR to include this feature:
https://jira.appcelerator.org/browse/AC-5653
https://github.com/appcelerator/titanium_mobile/pull/9927

JS/Angular - figure out how many html-elements are within the width/height of parent element

I am trying to create something like this here: https://www.amazon.de/Meisterwerke-Weltliteratur-Sammlung-internationaler-Meistererzählungen/dp/3839892716/
if you make the width of your browser-window smaller or bigger, you will notice the suffix of the authors-element (which is always one line) will say "X-authors hidden - show all". how can I calculate how many elements/authors are out of the bounds of the authors-parent-element, so I can tell the user how many he can expand by clicking on that suffix?
I use angular 4, but if you know the solution in plain JS, I might be able to translate it.
[EDIT]: I added two screenshots to show the effect, e.g. "& 16 mehr" and "& 14 mehr" (16 or 14 more in German).
and
Write a directive who will listen to window resize, something like:
#HostListener('window:resize', ['$event'])
onResize(event) {
const elementHeight = event.target.innerHeight;
const parentHeight = window.innerHeight;
const visibleElements = parentHeight / elementHeight;
const hiddenElements = Math.ceil(elementHeight - visibleElements);
console.log(hiddenElements);
}

Apply style to span based on number of lines within a cycling banner

Context
Here is a jsfiddle that I've been working with: http://jsfiddle.net/21r7uvgx/
For context, I'm using http://malsup.com/jquery/cycle/basic.html to make the rotating banner cycle through each <a> within the .custom-banners wrapper. I have the script as an external resource within the jsfiddle.
Starting Point
The idea is to make each span that has multiple lines (purely from window size) apply Style A, and those that have just one line apply Style B. Resizing the window changes what style each span gets.
I'm doing it to the span instead of the a based on the assumption that to achieve what I want, I need to target a element that displays as a block by default.
Issue and Goal
The issue I'm running into is that with the cycling script, a span that is not visible has a height of 0, so the math isn't right and it won't apply the correct style, even once the span becomes visible.
The goal is to find a way to have it check a span when it becomes visible, and apply the correct style.
Bonus Goal
If there's a better way to calculate the lineheight and determine what style needs to be applied, I'd also like those suggestions.
I was using this before, but it was very buggy when I manually resized the window.
var divheight = $(this).height();
var lineheight = $(this).css('line-height').replace("px","");
if (Math.round(divheight/parseInt(lineheight)) >= 2) {
$(this).attr('style','font-size: 10px');
} else {
$(this).attr('style','font-size: inherit');
};
Try this javascript. I have edited your javascript from the jsfiddle that you linked. If you don't want to change the font color (as in jsfiddle) and just want to change font size, then do it appropriately. Copy paste the below code to your jsfiddle and verify.
$(document).ready(function () {
$(window).on("resize", function () {
$('.custom-banners span').each(function () {
var lineheight = 20;
var divheight = $('.banner-link').height();
if (divheight > lineheight) {
$(this).css('color', 'red');
} else {
$(this).css('color', 'green');
};
});
});
});

Background position image overlay (Works in IE, not in Mozilla/Chrome/Safari)

I am having an issue positioning a background image using the following jquery background position command in Firefox, Google Chrome, and Safari. The code works correctly in IE 8.
$('#element').css({ backgroundPosition: 'xpx ypx' });
The desired effect is a continuous stream of fluid from the right side of the screen to the left, blurred out while behind the main page content. This is achieved using 2 fluid images, one completely sharp and one completely blurred. As the user resizes the window, a jquery function calculates the appropriate positioning of the blurred image (set as a background image) and edits the backgroundposition css attribute.
The x position of the image is calculated dynamically based on window size and the y position is static. The css appears to be modified correctly (note the backgroundposition display in the right most text box). However, the background image I am attempting to overlay is absent in mozilla/chrome/safari. See jscript code below:
$(window).resize(function () {
// image positioning variables
var windowwidth = $(window).width();
var imgwidth = $('#imgFluid').width();
var offset = $('#divFluidBlur').offset();
// calculate and implement position
blurPositionLeft = (windowwidth - imgwidth) - offset.left;
$('#divFluidBlur').css({ backgroundPosition: blurPositionLeft + 'px' + ' 30px' });
// debug: display actual css Background Position of element to text box
$("#txtActualBackgroundpos").val(document.getElementById ("divFluidBlur").style.backgroundPosition); }
Thanks in advance for your help,
Andrew
What you are doing should work. Anyway, you may want to try a little cleaner version: $('#divFluidBlur').css('background-position', blurPositionLeft + 'px' + ' 30px'); And you may want to use Firebug to temporary disable or change values of other styles that could be iterfering.
Could you privide an online example of the problem?

Categories