Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A Textbox with text wrapping and box resizing (subclasses IText) #1778

Closed
wants to merge 79 commits into from

Conversation

jafferhaider
Copy link
Contributor

For Issue 187. This is a more fully featured implementation than Pull Request 725.

I need this feature for my product, so I fully intend to support this class if it is made official.

Demo

Check it out a demo.

Summary of features

  • Subclasses IText, so gets all of its goodness.
  • Text wraps as user types and/or resizes a Textbox. Works with all textAlign values.
  • User can change width of Textbox. Height is automatically set based on text wrapping. Font size and scale does not change.
  • Support for resizing in Groups. Only the width of a Textbox changes. The Textbox updates its scaleX/Y values to undo scale values of its parent Group so that font size remains the same.
  • Refactored the ton of this.text.split(this._reNewline) calls into a function that gets overwritten by subclasses.
  • Fixed bug in Justify text (was present in both Text and IText classes).
  • Tested on latest versions of Safari (OSX & iOS), Chrome (OSX & Win), Firefox and Internet Explorer.

Open issues / TODOs

  1. Need to add support for Styles. It is not required for my usage of this widget so contributions are welcome.
  2. Justify alignment needs to be fixed in IText.
  3. Inheritance bug in IText.toSVG(). The callSuper in _setSVGTextLineText goes into a recursive loop if called on a Textbox object. It works fine if I replace the callSuper call with a call to a copy of Text._setSVGTextLineText. Have you encountered something like this before? Any opinions on how to fix this?

Please list changes that you'd like me to make before this can be made official. I saw in the other pull request that @kangax wasn't too sure about the 'Textbox' name ... we can change it.

@marcospassos
Copy link

@kangax please, could you take a look at this? This is something really wanted by a lot of users of this fantastic library.

@somecodemonkey
Copy link
Contributor

+1 cool i got this same feature in my app, it just doesn't support svg export. I ran into the same polymorphism issue but we didn't need it so i never attempted to fix it. You got a demo, i'd like to check it out?

@marcospassos
Copy link

@jafferhaider Could you provide us a demo? I'm very curious :)

@jafferhaider
Copy link
Contributor Author

Thanks for your interest guys. Link to demo added in the description above.

@jafferhaider
Copy link
Contributor Author

Added a point in the Open Issues section about how Textbox should behave when resized as part of a group. Would like your opinion on this @kangax.

@alanmastro
Copy link

This is a very important feature for many people! Merge! Merge! Merge!

@gunmetalremy
Copy link
Contributor

Wow this is amazing! Have you tried lucidpress? There is no scaling of the textboxes even in a group; the scaling remains 1 as you suggested. I highly recommend looking into their demo for reference.

@jafferhaider
Copy link
Contributor Author

@mochidusk yup, that is a appropriate UX. I'll implement this.

@kangax
Copy link
Member

kangax commented Oct 24, 2014

Will take a look as soon as I get a chance!

Sent from my iPad

On Oct 24, 2014, at 11:40 AM, Jaffer Haider notifications@github.com wrote:

@mochidusk yup, that is a appropriate UX. I'll implement this.


Reply to this email directly or view it on GitHub.

@marcospassos
Copy link

Congratulations, @jafferhaider. You work is just awesome!

Did you guys noticed that the justified alignment is not really justified in both sides?
justified

Normally, WYSIWYG editors align the text to the edge of both sides:

a-text_tool_08a

@marcospassos
Copy link

I just noticed a critical bug. If you try to resize the textbox for a very small size, that actually don't fit any word, the browser freezes (I'm running Chrome 38.0.2125.104 on a Macbook Pro 10.9.3).

@jafferhaider
Copy link
Contributor Author

Thanks for catching that @marcospassos. I've pushed a fix. The Textbox needed to have a minimum width, since it doesn't flip like other Canvas objects.

@jafferhaider
Copy link
Contributor Author

I've committed my initial pass at support for resizing Textboxes in a Group selection. Feedback on the UX is welcome. I've updated the demo with the latest code.

I had disabled flipping of Textboxes, but now that I had it working in Groups, I might remove the new 'minWidth' attribute in Textbox and enable flipping so it is more consistent with other Fabric objects. Basically I need to ensure Textbox works properly with the lockScalingFlip flag. Will work on it this week.

@marcospassos
Copy link

Fantastic work, @jafferhaider!

@artempartos
Copy link

👍

@PanfilovDenis
Copy link

👍 merge it please)

@Stefanoviic
Copy link

@asturur thanks.

You know why the iText padding isn't working? See here: https://jsfiddle.net/51u08n39/143/

@asturur
Copy link
Member

asturur commented Oct 20, 2015

Is not working because there i uploaded a too much devel version of fabric.
if you download the current version should work.

@Stefanoviic
Copy link

@asturur ah thanks got both the padding and canvas.toDataURL working now!

I've found a new problem though, which was working fine in 1.5.0.
If you type a very long word without spaces, the boundries of the width of the box are being ignored, see: https://jsfiddle.net/51u08n39/144/

@asturur
Copy link
Member

asturur commented Oct 20, 2015

Yes, of course, because the textbox cannot break words.
There is an ongoing proposal for word breaking:
#2376

with working code. Last version is better.

@Stefanoviic
Copy link

@asturur

Seems I cant give a fontFamily or fontSize to the whole textbox, only the first character.
Fill and align works properly though. (Worked fine in 1.5.0)

//Set Active Object Name
function setActiveProp(name, value) {
var object = canvas.getActiveObject();
if (!object) return;

object.set(name, value).setCoords();
canvas.renderAll();
}

//Add Controls
function addControls($scope) {

//Font Family
$scope.setFontFamily = function(value) {
    var count = canvas.getObjects().length - 1;
    var object = canvas.setActiveObject(canvas.item(count));
    $('#fontselect').css("font-family", value);
    setActiveProp('fontFamily', value);
    canvas.renderAll();
};  
//Change font color
$scope.changeFontColor = function() {     
    var count = canvas.getObjects().length - 1;
    var object = canvas.setActiveObject(canvas.item(count));    
    setActiveProp('fill', $('#hexVal').val());
    canvas.renderAll();
};
//Align left
$scope.alignLeft = function() {
    var count = canvas.getObjects().length - 1;
    var object = canvas.setActiveObject(canvas.item(count));    
    setActiveProp('textAlign', 'left');
};
//Align Center
$scope.alignCenter = function() {
    var count = canvas.getObjects().length - 1;
    var object = canvas.setActiveObject(canvas.item(count));    
    setActiveProp('textAlign', 'center');
};
//Align Right
$scope.alignRight = function() {
    var count = canvas.getObjects().length - 1;
    var object = canvas.setActiveObject(canvas.item(count));    
    setActiveProp('textAlign', 'right');
};  
//Font size
$scope.setFontSize = function(value) {
    var count = canvas.getObjects().length - 1;
    var object = canvas.setActiveObject(canvas.item(count));
    setActiveProp('fontSize', value);
    canvas.renderAll();
};      

}

@Stefanoviic
Copy link

Any chance someone knows why only the first character of my textbox is getting the font(size) if selected (See above)?

@asturur
Copy link
Member

asturur commented Oct 26, 2015

there is a bug i noticed and i should verify it again. if you change style of textbox, an array of styles get populated. This will not allow you anymore to change general fontsize.

Please try the latest version from githib, kangax builded it two days ago. then open a separate issue with a jsfiddle demonstrating the problem.

@Stefanoviic
Copy link

@asturur

Thanks, the newest fabricjs fixed the problem! But an old problem I had is back:

var dataURL = canvas.toDataURL({
format: 'jpeg',
quality: 1,
multiplier: 5
});

Seems the multiplier is not working...

@Stefanoviic
Copy link

@asturur you have any idea why the toDateURL is not being multiplied by the multiplier in the latest version?

@asturur
Copy link
Member

asturur commented Oct 27, 2015

not related on this post.

@manelio
Copy link

manelio commented Jan 23, 2016

Is there any news about this feature?

I see the pull request is closed, but I think it's very useful.

@asturur
Copy link
Member

asturur commented Jan 24, 2016

It has been merged and is now on main codebase.

@salmanjaved
Copy link

First of all this is great feature and awesome work. Few question regarding style and word break strategy:
1 - Unable to set style attribute of the object across each character.
2 - Also the fabricjs 1.6.0 release a breaking strategy on the basis of space. But the breaking strategy must be based on the number of character and their width like in the demo.

Any reason for these scenarios?

Thanks.

@asturur
Copy link
Member

asturur commented Apr 18, 2016

we implemented a non word breaking strategy. style should work. what
problem do you have with style?
On Apr 18, 2016 7:24 AM, "salmanjaved" notifications@github.com wrote:

First of all this is great feature and awesome work. Few question
regarding style and word break strategy:
1 - Unable to set style attribute of the object across each character.
2 - Also the fabricjs 1.6.0 release a breaking strategy on the basis of
space. But the breaking strategy must be based on the number of character
and their width like in the demo.

Any reason for these scenarios?

Thanks.


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#1778 (comment)

@abhi06991
Copy link

Is this feature available in the latest 1.6.2 version, cos it doesnt seem to work

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 251d5df on PosterMyWall:TextboxPullRequest into * on kangax:master*.

@akash31
Copy link

akash31 commented Sep 21, 2016

How to set fix height and width using fabric.Texbox.
I am trying to set fix height.

@asturur
Copy link
Member

asturur commented Sep 21, 2016

there is no fixheight.

@fahadnabbasi
Copy link

you need to override fabric.Textbox.prototype._initDimensions function and set the height of Textbox there
`(function() {
//Override function for textbox to handle the height for Textbox class

fabric.Textbox.prototype._initDimensions = function(ctx) {
    if (this.__skipDimension) {
        return;
    }

    if (!ctx) {
        ctx = fabric.util.createCanvasElement().getContext('2d');
        this._setTextStyles(ctx);
    }

    // clear dynamicMinWidth as it will be different after we re-wrap line
    this.dynamicMinWidth = 0;
    // wrap lines
    this._textLines = this._splitTextIntoLines();
    // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap
    if (this.dynamicMinWidth > this.width) {

            this._set('width', this.dynamicMinWidth);

    }
    // clear cache and re-calculate height
    this._clearCache();
    this.minHeight = this._getTextHeight(ctx);
    if(this.height <= 0)
        this.height=this.minHeight;
}

}).call(this);`

and after that when you are creating the new Textbox object, you need to define the height there

@akash31
Copy link

akash31 commented Sep 27, 2016

How to set Line wise text align using fabric.Textbox / Text / IText.
using Line Index.
Like., Left, Right, Center.

@asturur
Copy link
Member

asturur commented Sep 27, 2016

you can set it up only for all textbox with the .textAlign property.

www.fabricjs.com/docs

@akash31
Copy link

akash31 commented Sep 27, 2016

Yes I known but I need text align line index wise.

@asturur
Copy link
Member

asturur commented Sep 27, 2016

no.

@astw
Copy link

astw commented Oct 15, 2016

@asturur I tried your link below. When I try text into textbox, the textbox size changed if I type fast.

I noticed your demo is using version 1.6.1. So I create one using version 1.6.5, the issue still exists.

Is it a bug?

version 1.5.1 http://jsfiddle.net/51u08n39/142/
version 1.6.5 http://jsfiddle.net/astw/bhwypzfo/1/

@WilliamCarlos
Copy link

Is it possible to set a minimum height?

@asturur
Copy link
Member

asturur commented Jun 15, 2017

no. Not a functionality in fabric

@WilliamCarlos
Copy link

D: Any ideas for a workaround for dynamically adding textboxes to canvas (click and drag)?
Currently I'm setting the width/height of the textbox from mouse:move but setting the height doesn't do much (since it auto-resizes height to the default text).

@asturur
Copy link
Member

asturur commented Jun 15, 2017

You need to extend the object changing some behaviour you do not like. is way better than trying to hack it with events.

Please if you are starting a project, do it on the 2.0 branch, text works way better.

@fahadnabbasi
Copy link

fahadnabbasi commented Jun 15, 2017 via email

@IMPMAC
Copy link

IMPMAC commented Jun 27, 2017

Hi, I am hoping someone can help me here.

I am clicking and then adding a new textbox that is at first empty. I have written code to automatically enter editing mode

My issue is that when you press space, it wraps the text. I only want it to wrap when the user presses return or manually resizes the textbox.

Is there anything I can do/start to get this behaviour?

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet