The objective of this jsfiddle is the following:
User clicks on canvas
A cursor shows up where the user clicked
User can enter text
I tried to use IText enterEditing method right after the user clicks on the canvas, but the cursor does not show up, so the user don't know they can enter text. In addition, in Chrome and Firefox the user cannot enter text at all. Any ideas?
Javascript
var canvas = new fabric.Canvas('c');
canvas.on('mouse:down', function(options) {
if (options.target == null)
addText(options.e);
});
function addText(e) {
var text = new fabric.IText('',{
left: e.offsetX,
top: e.offsetY
});
canvas.add(text);
text.enterEditing();
}
Try the following code, you need to set your text object as active object in canvas.
var text = new fabric.IText('',{
left: e.offsetX,
top: e.offsetY
});
canvas.add(text).setActiveObject(text);
text.enterEditing();
Try this fiddle i upaded using this code,Hope it can help you somewhat
var canvas = new fabric.Canvas('c');
canvas.on('mouse:down', function(options) {
if (options.target == null)
addText(options.e);
});
function addText(e) {
var custontxt=new fabric.IText('Tap and Type', {
fontFamily: 'helvetica',
fontSize:30,
fontWeight:400,
fill:'red',
fontStyle: 'normal',
top:250,
cursorDuration:500,
left:250,
});
canvas.add(custontxt);
}
http://jsfiddle.net/hsLwjtbx/16/
Related
fabricjs_2.3.6
I am working on an editor that will allow the user to create textboxes images and rectangles dynamically and that portion of the project works great. All objects on the canvas will pre-existing before creating groups therefore I do not want to hard-code any fabrics. I also want to preserve the positional relation between the grouped items.
I am having a problem with creating groups by selecting 2 or more existing objects on the canvas to create a group. My code works with one exception, if the selected items are not in the upper left corner of the canvas when I create the group the grouped objects remain in the original location as desired but the move handle is in the upper left corner of the canvas. If you click the move cursor handle ghost and then click a blank area on the canvas the problem goes away and everything works fine after that.
I have had no luck searching for a solution possibly because I'm not sure what controls the move cursor's location on the canvas or if it is actually called the "move cursor".
Here is a picture from my jsfiddle after clicking the group button:
Here is a jsfiddle link to demonstrate the problem: https://jsfiddle.net/Larry_Robertson/xfrd278a/
Here is my code:
HTML
<span> Test 1: select both the line and the text objects with the mouse then click group, works great.</span>
<br/>
<span> Test 2: select both the line and the text objects with the mouse, move the selction to the center of the canvas then click group. This creates the problem where a ghost move handle is left behind in the upper left corner of the canvas. The move handle did not update to the correct position when the group was created. If you hover the mouse in the upper left of canvas you will see the move cursor. Click on the move cursor then click any blank part of the canvas then you can reselect the group and it moves properly. What am I doing wrong???</span>
<br/>
<button id="group">group</button>
<canvas id="c" height="300" width="500"></canvas>
JS
var canvas = new fabric.Canvas('c');
var text = new fabric.Text('hello world', {
fontSize: 30,
originX: 'left',
originY: 'top',
left: 0,
top: 0
});
var line = new fabric.Line([10, 10, 100, 100], {
stroke: 'green',
strokeWidth: 2
});
canvas.add(line);
canvas.add(text);
canvas.renderAll();
$('#group').on(("click"), function(el) {
var activeObject = canvas.getActiveObject();
var selectionTop = activeObject.get('top');
var selectionLeft = activeObject.get('left');
var selectionHeight = activeObject.get('height');
var selectionWidth = activeObject.get('width');
if (activeObject.type === 'activeSelection') {
var group = new fabric.Group([activeObject], {
left: 0,
top: 0,
originX: 'center',
originY: 'center'
});
canvas.add(group);
deleteSelectedObjectsFromCanvas();
canvas.setActiveObject(group);
group = canvas.getActiveObject();
group.set('top', selectionTop + (selectionHeight / 2));
group.set('left', selectionLeft + (selectionWidth / 2));
group.set('originX', 'center');
group.set('originY', 'center');
canvas.renderAll();
}
});
function deleteSelectedObjectsFromCanvas() {
var selection = canvas.getActiveObject();
var editModeDected = false;
if (selection.type === 'activeSelection') {
selection.forEachObject(function(element) {
console.log(element);
if (element.type == 'textbox') {
if (element.isEditing == true) {
//alert('At least one textbox is currently being edited. No objects were deleted');
editModeDected = true;
}
}
});
if (editModeDected == true) {
return false;
}
// Its okay to delete all selected objects
selection.forEachObject(function(element) {
console.log('removing: ' + element.type);
//element.set('originX',null);
//element.set('originY',null);
canvas.remove(element);
canvas.discardActiveObject();
canvas.requestRenderAll();
});
} else {
if (selection.isEditing == true && selection.type == 'textbox') {
//alert('Textbox is currently being edited. No objects were deleted');
} else {
canvas.remove(selection);
canvas.discardActiveObject();
canvas.requestRenderAll();
}
}
}
CSS
#c {
margin: 10px;
padding: 10px;
border: 1px solid black;
}
After making changes on code always do a setCoords on the object(s) that got changed.
Here is a one liner you can add after the renderAll to fix your issue:
...
group.set('originY', 'center');
canvas.renderAll();
canvas.forEachObject(function(o) {o.setCoords()});
I'm importing several svgs that are all created from the same image and layered on top of each other. I would like to add text centered over a certain svg/textarea path. And then scale textarea to fit the text provided with a min size. And ive confused myself. I have no idea anymore? I deleted everything and started over direction would be very helpful. Heres what i got.
var canvas = new fabric.Canvas('canvas');
fabric.loadSVGFromURL('/1-man.svg', function(objects, options) {
var obj = fabric.util.groupSVGElements(objects, options);
canvas.add(obj).renderAll();
});
fabric.loadSVGFromURL('/1-man-cutout.svg', function(objects, options)
{
var obj = fabric.util.groupSVGElements(objects, options);
canvas.add(obj).renderAll();
});
fabric.loadSVGFromURL('/textarea.svg', function(objects, options) {
var obj2 = fabric.util.groupSVGElements(objects, options);
canvas.add(obj2).renderAll();
});
var text = new fabric.Text("Hello", {
fontFamily: 'ubuntu',
fontSize: 300,
textAlign: "center",
});
canvas.add(text);
Brain was dead i suppose.... took about a min this morning.. Ill keep it for a lesson on sleeping on it.
text.set('left', (objects[0].width - text.width)/2);
text.set('top', objects[0].top + 5);
canvas.add(obj2, text).renderAll();
could someone please point me in the direction for how to enable double click on fabric images? i came across this solution
FabricJS double click on objects
I am trying to not use FabicjsEx
but i am unable to get anything to work correctly. can someone please let me know the best way to accomplish this?
The best way to accomplish this, is to use fabric.util.addListener method.
Using that you could add a double click event for the canvas element and to restrict it to any particular object ( ie. image ), you would have to check whether you clicked on an image object or not before performing any action.
ᴅᴇᴍᴏ
var canvas = new fabric.Canvas('canvas');
// add image
fabric.Image.fromURL('https://i.imgur.com/Q6aZlme.jpg', function(img) {
img.set({
top: 50,
left: 50
})
img.scaleToWidth(100);
img.scaleToHeight(100);
canvas.add(img);
});
// add rect (for demo)
var rect = new fabric.Rect({
left: 170,
top: 50,
width: 100,
height: 100,
fill: '#07C'
});
canvas.add(rect);
// mouse event
fabric.util.addListener(canvas.upperCanvasEl, 'dblclick', function(e) {
if (canvas.findTarget(e)) {
const objType = canvas.findTarget(e).type;
if (objType === 'image') {
alert('double clicked on a image!');
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.js"></script>
<canvas id="canvas" width="320" height="200"></canvas>
This is not Drawing Mode.
I want according to some condition to be able to change the cursor when I am over some element. Something like
$('#canvasID').css('cursor','pointer');
but this is not working for me. Do you know some property from their library?
After some tests this is working for me:
canvas.observe('mouse:over', function (e) {
if (e.target.get('type') == 'line') {
e.target.hoverCursor = 'crosshair';
}
});
FabricJS have an in-built mechanism for setting custom cursor (unfortunatelly only for hover and move events):
var canvas = new fabric.Canvas('myCanvas');
var circle = new fabric.Circle({
radius: 20, fill: 'red', left: 10, top: 10
});
circle.hoverCursor = 'no-drop';
canvas.add(circle);
More cursor types you can find here.
I have a canvas built using fabricJS with the dimension of 600x500. I have added an image to this canvas which is of size 200x300 and also a text element just below it.
$canvasObj.toDataURL();
exports the whole canvas area including the white spaces surrounding the design on the canvas.
Is there a way to get the cropped output of the design on the canvas alone instead of all the whitespace?
This can be done by cloning objects to a group, getting the group boundingRect, and then passing the boundingRect parameters to toDataUrl() function (see fiddle).
e.g.
// make a new group
var myGroup = new fabric.Group();
canvas.add(myGroup);
// ensure originX/Y 'center' is being used, as text uses left/top by default.
myGroup.set({ originX: 'center', originY: 'center' });
// put canvas things in new group
var i = canvas.getObjects().length;
while (i--) {
var objType = canvas.item(i).get('type');
if (objType==="image" || objType==="text" || objType==="itext" || objType==="rect") {
var clone = fabric.util.object.clone(canvas.item(i));
myGroup.addWithUpdate(clone).setCoords();
// remove original lone object
canvas.remove(canvas.item(i));
}
}
canvas.renderAll();
// get bounding rect for new group
var i = canvas.getObjects().length;
while (i--) {
var objType = canvas.item(i).get('type');
if (objType==="group") {
var br = canvas.item(i).getBoundingRect();
}
}
fabric.log('cropped png dataURL: ', canvas.toDataURL({
format: 'png',
left: br.left,
top: br.top,
width: br.width,
height: br.height
}));
p.s. I should probably mention that i've not worked with image types, so i just guessed that it's called 'image'..