I'm working on project for Canvas editor.I have this issue :User can add text and edit it in canvas but when delete first text and try to put again text,new text can't be edit.I use fabricjs.
For add text i use this code.
$("#addText").on("click", function addText() {
var oText = new fabric.IText('Tap and Type', {
left: 100,
top: 100,
fontSize: 26,
});
oText.set({ fill: $(".addText-options .sp-preview-inner").css("background-color") });
oText.id = 'userDesign';
canvas.add(oText).renderAll().setActiveObject(oText);
activeObject = canvas.getActiveObject();
});
I found the solution.The problem was in version of fabricjs i used i just change version.
Related
I'm attempting to add a loaded image into a fabric Group object. Everything looks ok, but the selection controls aren't selectable and I can't drag the object around. The top left control works though and after clicking it everything is fine.
Here is a jsfiddle that demonstrates the behavior.
var canvas = new fabric.Canvas('canvas', {
width: 200,
height: 200
});
var group = new fabric.Group();
canvas.add(group);
fabric.Image.fromURL('https://placehold.it/100x100', function(img) {
group.addWithUpdate(img);
canvas.setActiveObject(group);
canvas.renderAll();
});
Is this a bug or am I doing something wrong?
For some performance reason, fabricjs does not call setCoords automatically after adding objects to a group ( in case of many object added you can call setCoords just once ).
So after doing addWithUpdate, just call group.setCoords();
var canvas = new fabric.Canvas('canvas', {
width: 200,
height: 200
});
var group = new fabric.Group();
canvas.add(group);
fabric.Image.fromURL('https://placehold.it/100x100', function(img) {
group.addWithUpdate(img);
group.setCoords();
canvas.setActiveObject(group);
canvas.renderAll();
});
I came across this post because I was having trouble getting the positioning of images to work properly. I ended up finding that it's easier to just create create an image element using document.createElement and set the src, then feed that into fabric.Image with all the options you need (instead of using fabric.Image.fromURL which was too much of a headache to use), before adding it to the group.
var oImg = document.createElement("img");
oImg.setAttribute('src', 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/92/Cog_font_awesome.svg/512px-Cog_font_awesome.svg.png');
var i = new fabric.Image(oImg, {
originX: 'center',
originY: 'center',
left: left+35,
top: top-30,
scaleX:.05,
scaleY:.05,
});
g = new fabric.Group([r, t, i]); // where r and t are other fabric objects
I am creating an application for T-shirt customization in which I have put the canvas on image using CSS, but the problem is saving that image as canvas. toDataURL just gives part of the canvas area, but I want the whole image. There are other solutions on Stack Overflow but they do not solve this problem.
Hello,
you have to create an image object (tshirt) with a text object that holds the message.
to do that , load the image with fabric.Image.fromURL() function and inside the function , also create a text object that is going to show the tshirt message.
so, your image and text belong to a group object.
every time you want to load new text , you call the loadText function and you change the text object.
i also added 4 buttons in order to manupulate up/down/left/right the text .
you can export the canvas + image+ text into the function saveImg(),
but on the jsfiddle you will get a security message for Tained canvases.
that happens because on the example i load the image from another domain and the code runs on another domain, you can run that code on your web application with no problem at all.
that is the code :
var canvas = new fabric.Canvas('c');
var scaleFactor=0.4
canvas.backgroundColor = 'yellow';
canvas.renderAll();
var myImg = 'http://izy.urweb.eu/files/tshirt.jpg';
fabric.Image.fromURL(myImg, function(myImg) {
var img1 = myImg.scale(scaleFactor).set({ left: 0, top: 0 });
var text = new fabric.Text('the_text_sample\nand more', {
fontFamily: 'Arial',
fontSize:20,
});
text.set("top",myImg.height*scaleFactor-myImg.height*scaleFactor+150);
text.set("left",myImg.width*scaleFactor/2-text.width/2);
var group = new fabric.Group([ img1,text ], { left: 10, top: 10 });
canvas.add(group);
});
$('#loadText').on('click',loadText);
$('#saveImg').on('click',saveImg);
function loadText(){
console.log($('#logo').val());
canvas._objects[0]._objects[1].text = $('#logo').val();
canvas.renderAll();
}
function saveImg(){
console.log('export image');
if (!fabric.Canvas.supports('toDataURL')) {
alert('This browser doesn\'t provide means to serialize canvas to an image');
}
else {
window.open(canvas.toDataURL('png'));
}
}
$('#left').on('click',function(){
canvas._objects[0]._objects[1].set('left',canvas._objects[0]._objects[1].left-1);
canvas.renderAll();
})
$('#right').on('click',function(){
canvas._objects[0]._objects[1].set('left',canvas._objects[0]._objects[1].left+1);
canvas.renderAll();
})
$('#top').on('click',function(){
canvas._objects[0]._objects[1].set('top',canvas._objects[0]._objects[1].top-1);
canvas.renderAll();
})
$('#bottom').on('click',function(){
canvas._objects[0]._objects[1].set('top',canvas._objects[0]._objects[1].top+1);
canvas.renderAll();
})
that is the jsfiddle example: http://jsfiddle.net/tornado1979/zrazuhcq/1/
hope helps, good luck.
Sorry for my bad English.
I want to learn the use of fabric.js.
For the basic commands I haven't had any problem. But I now have this problem.
I have two button in the index.html file :
<tr>
<td><button id="caricarettangolo" onMouseDown="caricarettangolo(), caricatutto()" type="button"><img src="immagini/prodotti/rettangolo.svg" /></button></td></tr>
<tr>
<td><button type="button" onMouseDown="caricastella()"><img src="immagini/prodotti/stella.svg" /></button></td></tr>
</tr>
and external js file with this code
function caricacerchio() {
var canvas = new fabric.Canvas('canvas');
var circle = new fabric.Circle({
radius: 20, fill: 'green', left: 100, top: 100
});
canvas.getObjects();
canvas.add(circle);
canvas.selection = false;
canvas.renderAll();
canvas.calcOffset();
};
function caricarettangolo() {
var canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
width: 50,
height: 50,
left: 50,
top: 50,
fill: 'rgb(255,0,0)'
});
canvas.getObjects();
canvas.add(rect);
canvas.selection = true;
canvas.renderAll();
canvas.calcOffset();
};
But I don't have the solution for seeing two elements.
I see the first element, next, if i push another button, this completely clears the canvas and adds the new element, but clears the first element. If I click in the canvas square, return the first created element. Why? As I can see when I have two different buttons two different element? Thanks.
You're rendering on a new canvas every time you press the button:
var canvas = new fabric.Canvas('canvas');
You want to render the canvas outside of your functions
window.canvas = new fabric.Canvas('canvas');
then use the buttons to add them.
You can see an example here: http://jsfiddle.net/33MME/2/
I am looking for an example application that takes user input and inserts it into a inside canvas with fabric.js. Is this possible? I haven't been able to find a lists in fabric.js example.
canvas.fillText does not accept HTML markup.
A Canvas is a bitmap, it has nothing to do with HTML markup.
You can control font style as described here.
There are libraries that convert XML markup into canvas.fillText calls, maybe you could adapt one.
I realized a better way to solve this issue was to draw a circle at the same height as the text, at radius 2, to emulate a bullet point. for anybody interested its easy as:
var EDU1 = new fabric.IText("SOME TEXT GOES HERE", {fontSize: 20, fontStyle:
'italic',fontFamily: 'Hoefler Text', left: 149, top: 390});
var bullet = new fabric.Circle({
radius: 2, fill: 'black', left: 135, top: 400
});
then group them together and you have a bullet point.
function ListStyle (textObject,type,canvas) {
var styles=['\u25CF','\u25C8','\u25D8','\u25BA','\u25CB','\u25A0','-'];
var allStyles={'bullet':'\u25CF','diamond':'\u25C8','invertedBullet':'\u25D8','triangularBullet':'\u25BA','disced':'\u25CB','squared':'\u25A0','dashed':'-','none':''};
var text = textObject.text;
var textArray = text.split('\n')
var tempStr = [];
textArray.forEach((text, i) => {
if(styles.includes(text.substr(0,1))){
tempStr.push(text.replace(text.substr(0,1),allStyles[type]));
}else{
tempStr.push(allStyles[type]+''+text);
}
})
textObject['text'] = tempStr.join('\n');
canvas.renderAll();
}
ListStyle (canvas.getObjects()[0],'diamond',canvas);
I want to add Textbox or editable element to give the user the option to edit the text.
This is my current code:
var text = new Kinetic.Text({
text: "Sample Text", ---> i want to edit this text
x: 50,
y: 10,
fill: "transparent",
fontSize: 10,
fontFamily: "Helvetica Neue",
textFill: "#000",
align: "center",
verticalAlign: "middle",
name:'TEXT'
});
At the moment there does not seem to be any way to create editable text with Kinetic JS (see several threads about this at stackoverflow), some people suggest using an input field next to the canvas to edit the text, but my solution would be the following:
create a text with your code
on text click [text.on("click", function...], create an input field right at your mouse cursor
Well, that´s the plan. Maybe it´s easier to use a "save" button text to the input field, so you know exactly when to close it and when to store the input field data to the Kinetic text. you would also need a "close" function if you don´t want to edit it.
A very easy solution would also be a simple JavaScript prompt:
var xy = prompt("gimme your text");
So, something like this would be the best Solution imho:
myText.on('click', function(evt) {
this.setText(prompt('New Text:'));
layer.draw(); //redraw the layer containing the textfield
});
I've made an attempt for an actual KinetiJS plugin with editable text functionality.
I know it's reinventing the wheel, when you can just hover a textarea, but why not have it only in canvas too.
Check the plugin out at: https://github.com/nktsitas/kineticjs-editable-text
I did this some days back on my project. Hare are the code snippets. Basically we first draw the rectangle and then put a text area inside it and finally convert it into kinetic.text node.
drawText: function ( color )
{
var layer1=this.model.stage.getLayers()[0];
var $this=this;
console.log('drawText: color: ' + color);
if($this.rectangleDrawn==true)
{
var down = false, oPoint;
layer1.off("mousedown touchstart mousemove touchmove mouseup touchend");
if(group!=undefined && group!='')
{
$this.hideAnchors(group);
}
console.log("textX: "+textX);
//after rectangle is drawn we now have to add the editablesection
$('<textarea id="text" type="text" width='+textWidth +'px height='+textHeight+'px style="font-size: 30px;font-family:Calibri;height:'+textHeight+'px;width:'+textWidth+'px;position:absolute'+';left:'+textX+'px'+';top:'+textY+'px'+';z-index:5'+';background-color:#ffcc00;"></textarea>')
.insertBefore('.kineticjs-content');
$('#text').on('blur',function()
{
console.log("textchange");
text = new Kinetic.Text( {
x: textX,
y: textY,
stroke: color,
strokeWidth: 1,
fontSize: 30,
fontFamily: 'Calibri',
clearBeforeDraw: false,
name: 'image'+layer1.getName(),
draggable: true,
height: textHeight,
width: textWidth,
text: $('#text').val()
} );
text.on( 'mouseleave dbltap', function ()
{
text=this;
} );
$('#text').remove();
layer1.add( text );
layer1.draw();
})
},drawRectangle: function ( opacity, colorFill,stroke,textColor ){rect = new Kinetic.Rect({
x: mousePos.x,
y: mousePos.y,
width: 0,
height: 0,
stroke: stroke,
strokeWidth: 4,
opacity: opacity,
clearBeforeDraw: false,
name: 'image'+layer1.getName()
});
layer1.on( "mouseup touchend", function ( e )
{
console.log("rectangle: mouseup");
console.log("width: "+rect.getWidth( ));
rect.setOpacity(opacity);
rect.setFill(colorFill);
layer1.draw();
down = false;
console.log("textColor: "+textColor)
if(textColor!=undefined)
{
textWidth=rect.getWidth( );
textHeight=rect.getHeight( );
textX = rect.getAbsolutePosition().x;
textY=rect.getAbsolutePosition().y;
$this.rectangleDrawn=true;
$this.drawText(textColor);
console.log("textdrawn ");
$this.group.remove();
}
},