I want to programmatically select Fabrics.js object. What do I have to do? For example, I am adding two objects like this:
var canvas = new fabric.Canvas('canvas');
canvas.add(new fabric.Rect({
left: 100,
top: 100,
width: 75,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 3,
padding: 10
}));
canvas.add(new fabric.Circle({
left: 200,
top: 200,
radius: 30,
fill: 'gray',
stroke: 'black',
strokeWidth: 3
}));
and I have two button while clicking the button named
select rectangle
select second object
While clicking the select rectangle button it should select the rectangle shape and while clicking the select second object button it should select the second object circle.
Here is the Jsfiddle for workaround.
I goggled and fed up, here I am seeking for some point how to start.
EDIT
I like to have the ID for each object, it should be possible to select the object using that ID, why I am asking this is, while using the collaborative things we can't tell surely all the connected nodes will have the item in same index, so unique id will be useful.
You want to use:
canvas.setActiveObject(canvas.item(0));
In the buttons click event
The number corresponds to the order in which the object was added to the canvas.
See here:
http://jsfiddle.net/ThzXM/1/
Yes, you can set id for each item by adding the below code in all.js
In the fabric.js build version 1.3.0 : In the Object declaration add
var object = {
id: this.id,
remaining properties in all.js
}
Now you can set the object id with:
canvas.getActiveObject().id=your id value;
You can retrieve the object id with :
Myid= canvas.getActiveObject().get('id');
To find the fabric object number (item number) of the selected object use:
canvas.on({
'object:selected': selectedObject
});
function selectedObject(e) {
var id = canvas.getObjects().indexOf(e.target);
}
var id is the same number if you programmatically set the object as in Dan Brown's reply:
canvas.setActiveObject(canvas.item(id)); //id = 0, 1, 2 etc.
add an id to your objects.
var canvas = new fabric.Canvas('canvas');
canvas.add(new fabric.Rect({
id: 123,
left: 100,
top: 100,
width: 75,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 3,
padding: 10
}));
canvas.add(new fabric.Circle({
id: 456,
left: 200,
top: 200,
radius: 30,
fill: 'gray',
stroke: 'black',
strokeWidth: 3
}));
function removeSpot(canvas, id) {
canvas.forEachObject(function(obj) {
if (obj.id && obj.id === id) canvas.remove(obj);
});
}
// remove rect
removeSpot(canvas, 123);
// remove circle
removeSpot(canvas, 456);
Related
I have the button which add new group which have square, to layer when clicked very simple code I guess no need to post. But my question is that how can I add transformer to it when on clicked?, I have done it with this mouseleave and mouseenter functions.
group.on('mouseenter', () => {
transformer.borderEnabled(true);
transformer.resizeEnabled(true);
layer.draw();
});
group.on('mouseleave', () => {
transformer.borderEnabled(false);
transformer.resizeEnabled(false);
layer.draw();
});
It is in loop which creates new group named "group", It works fine but in circle when I hover it the transformer appears but then when I go to transformer's boxes to resize it consider as it is mouseleave but this is doing only in circle not in line text.
So can I have solution for active transformer on element which is clicked or for considering hover on transformer boxes as a hover on node? Thanks
The mouseleave() will always fire because the pointer must leave the group to use the transformer handles or spinner.
An alternative approach would be
click to enable the transformer,
leave the transformer in place even when the mouse moves away
wait for a click on some other shape to know you can hide the transformer.
That is the standard GUI approach I believe.
If you need to show hover focus then stick a transparent rectangle the size of the groups clientrect into the group and change its stroke from transparent to some colour in the mouseenter and back in the mouseleave. You will also maybe want to set the rect.listening to false so as it coes not interfere with mouse events on the shapes in the group, but then again it might help in dragging.
Demo below.
// Set up the canvas and shapes
let stage = new Konva.Stage({container: 'container1', width: 300, height: 200});
let layer = new Konva.Layer({draggable: false});
stage.add(layer);
// Add a transformer.
let transFormer1 = new Konva.Transformer();
layer.add(transFormer1);
// Create a sample group
let group1 = new Konva.Group();
layer.add(group1);
group1.add(new Konva.Circle({x: 20, y: 30, radius: 15, fill: 'magenta', stroke: 'black'}))
group1.add(new Konva.Circle({x: 60, y: 40, radius: 15, fill: 'magenta', stroke: 'black'}))
group1.add(new Konva.Rect({x: 90, y: 60, width: 25, height: 25, fill: 'magenta', stroke: 'black'}));
let pos = group1.getClientRect();
let boundRect1 = new Konva.Rect({name: 'boundRect', x: pos.x, y: pos.y, width: pos.width, height: pos.height, fill: 'transparent', stroke: 'transparent'});
group1.add(boundRect1);
// When mouse enters the group show a border
group1.on('mouseenter', function(){
let boundRect = this.find('.boundRect');
boundRect[0].stroke('red');
layer.draw();
})
// and remove border when mouse leaves
group1.on('mouseleave', function(){
let boundRect = this.find('.boundRect');
boundRect[0].stroke('transparent');
layer.draw();
})
// If the group is clicked, enable the transformer on that group.
group1.on('click', function(){
transFormer1.attachTo(this)
layer.batchDraw();
})
// For a more pleasing demo let us have 2 groups.
// Make a copy of group1, offset new group, and change fill on its child shapes except the bound rect
let group2 = group1.clone();
layer.add(group2)
group2.position({x: 120, y: 30});
for (let i = 0, shapes = group2.getChildren(); i < shapes.length; i = i + 1){
shapes[i].fill(shapes[i].fill() !== 'transparent' ? 'cyan' : 'transparent');
}
stage.draw();
<script src="https://unpkg.com/konva#^3/konva.min.js"></script>
<p>Move mouse over the shapes to see the group borders, click a group to apply the transformer.
</p>
<div id='container1' style="display: inline-block; width: 300px, height: 200px; background-color: silver; overflow: hidden; position: relative;"></div>
Got the answer!, I just create a public transformer and on stage click I am adding nodes to it no transformer to each group just one public transformer which hold one node at a time.
I am adding one Image on Canvas. I am using FabricJS on Frontend and Laravel on the backend.
I want to change the color and style of the control's broder.
Here is my Object in Fabric JS
var homeImage = new fabric.Image(homeImgElement, {
left: -10,
top: -10,
angle: 0,
width:620,
height:500,
});
You can check Fabric JS document for more control options.
Here you go.
You can even use property which is corderSize.
var homeImage = new fabric.Image(homeImgElement, {
left: -10,
top: -10,
angle: 0,
width:620,
height:500,
borderColor: #000,
cornerColor: #DDD,
cornerStyle:'circle',
cornerSize:5,
});
I am having problem with grouping multiple objects on canvas. When I select objects using holding down shift key and then if I make a group of those objects, the newly added group has incorrect z-index of it's items. Pleas run the snippet bellow to understand the problem.
Please select green box first, then select blue and then red while the shift key is pressed. Then clik on Group button to see the problem.
canvas = new fabric.Canvas('canvas', {
isDrawingMode: false,
preserveObjectStacking: true
});
fabric.Object.prototype.objectCaching = true;
canvas.setWidth(380);
canvas.setHeight(310);
canvas.setBackgroundColor('#F2F2F2');
canvas.renderAll();
var topMost = new fabric.Rect({
left: 90,
top: 90,
width: 50,
height: 50,
fill: 'green',
});
var middle = new fabric.Rect({
left: 70,
top: 70,
width: 50,
height: 50,
fill: 'blue',
});
var bottom = new fabric.Rect({
left: 50,
top: 50,
width: 50,
height: 50,
fill: 'red',
});
canvas.add(bottom);
canvas.add(middle);
canvas.add(topMost);
$(".group").on('click', function () {
var activegroup = canvas.getActiveGroup();
var objectsInGroup = activegroup.getObjects();
activegroup.clone(function (newgroup) {
canvas.discardActiveGroup();
objectsInGroup.forEach(function (object) {
canvas.remove(object);
});
canvas.add(newgroup);
});
});
h3{color: blue;}h5{color: red;}canvas{border: 2px solid black;}
button{padding: 8px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
<h3>Please select green box first, then select blue and then red while the shift key is pressed. Then clik on Group button to see the problem</h3>
<h5>Problem: Grouping multiple objects, selected using shift key down, changes their z-index after grouped</h5>
<button class="group">Group</button>
<canvas id="canvas"></canvas>
Fabric has never automatically preserved object order in groups. I see you were using preserveObjectStacking = true, and I think this might have caused your confusion. This property does not affect the actual order of the objects to "preserve" the way they are on the canvas. Instead, it changes the order the objects appear to have while selected, as well as the click-target-finding when clicking on these objects.
Objects in the active selection are added in the order of clicking, and adding with preserveObjectStacking, they get rendered in canvas order. The first 2 objects get ordered in stack order anyway.
In your specific case, you click
green -> activeObject
blue -> blue is under green so you get activeGroup with blue, green.
red -> red gets pushed in active group at end of objects array.
The order that you get when you clone is exactly blue, green, red.
To preserve the order that the objects have on the canvas, you can easily write a sort function and run it against your group's objects before cloning it.
var sorter = function (a, b) {
var idxA = canvas._objects.indexOf(a),
idxB = canvas._objects.indexOf(b);
return idxA > idxB ? 1 : 0;
};
var activegroup = canvas.getActiveGroup();
activegroup._objects.sort(sorter);
var objectsInGroup = activegroup.getObjects(); //these are now in the canvas's order
//.....continue with your original code
I am working on titanium and creating view from controller. I have four fields and i need to set values with their IDs. Please check following code
var row = Ti.UI.createTableViewRow();
var first_name = Ti.UI.createTextField({
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED,
color: 'black',
top: 10,
left: 10,
width: 250,
height: 60,
id:'first_name',
//value:data.first_name
});
row.add(first_name);
var tbl_data=[];
tbl_data.push(row);
var tbl= Ti.UI.createTableView({
data:tbl_data
});
$.home_view.add(tbl);
The id:'first_name' does not seem to work and i have not found any example where an ID is being assigned to any UI element. Please guide
You can't set ID. But there are 2 options
1: Don't make an input in the controller, but make it a separate controller instead (see my blogpost on reusable components)
2: Just set it like this:
$.first_name = Ti.UI.createTextField({
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED,
color: 'black',
top: 10,
left: 10,
width: 250,
height: 60
});
Then you can reference it later, like this: $.first_name.value;
You can also set a custom property to the create function (any property works fine) and identify it with that using events. Like this:
var field = Ti.UI.createTextField({
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED,
color: 'black',
top: 10,
left: 10,
width: 250,
height: 60,
textFieldId: 'first_name'
});
field.addEventListener('blur',function(e){
var id = e.source.textFieldId;
});
I have some text, that has a class in the form of "link variabletext" (where variabletext is unique to each link). I'm trying to set this up so that when I mouseover the text, the corresponding object changes color, using jQuery.
A jsFiddle of what I have: http://jsfiddle.net/hdJCn/
The code I'm using:
One
Two
Three
<div id="container"></div>
var stage = new Kinetic.Stage({
container: 'container'
});
var layer = new Kinetic.Layer();
var onecircle = new Kinetic.Ellipse({
x: 100,
y: 100,
radius: {
x: 50,
y: 50
},
strokeWidth: 1,
stroke: 'black'
});
layer.add(onecircle);
stage.add(layer);
$('.link').mouseover(function () {
var numclass = $(this).attr('class').split(' ')[1];
(numclass + 'circle').setStroke('orange');
});
The problem is that it says that the object has no method "setStroke". If I take that same object name and hardcode it (so onecircle.setStroke instead of the above) it works fine. I'm not sure why this is and so far am at a loss.
Figured it out. I had to convert the string to an object:
var obj = eval(numclass+'circle');
And then use obj.setStroke....