var canvas = new fabric.Canvas();
// select all objects
function selectAllCanvasObjects(){
var objs = canvas.getObjects().map(function(o) {
return o.set('active', true);
});
var group = new fabric.Group(objs, {
originX: 'center',
originY: 'center'
});
canvas._activeObject = null;
canvas.setActiveGroup(group.setCoords()).renderAll();
}
I have a canvas and I need to select all text objects and skip others. This is the code to select all objects, how can I make it only select all text objects and skip others?
The following example only selects items with the type of 'text'.
In summary:
The Fabric JS get method allows us to inspect the type of the current item that we're iterating over
If the type is equal to 'text' then we return the item
N.B. We now use filter instead of map, as we now only want to return items that match the type of 'text', instead of every item
var canvas = new fabric.Canvas('c');
// Add some example shapes
var circle = new fabric.Circle({
radius: 20, fill: 'green', left: 100, top: 100
});
var triangle = new fabric.Triangle({
width: 20, height: 30, fill: 'blue', left: 50, top: 50
});
canvas.add(circle, triangle);
// Add some example text
var text1 = new fabric.Text('hello world', { left: 100, top: 100 });
var text2 = new fabric.Text('test', { left: 0, top: 0 });
canvas.add(text1, text2);
// Select all objects
function selectAllCanvasObjects(){
var objs = canvas.getObjects().filter(function(o) {
if (o.get('type') === 'text') {
return o.set('active', true);
}
});
var group = new fabric.Group(objs, {
originX: 'center',
originY: 'center'
});
canvas._activeObject = null;
canvas.setActiveGroup(group.setCoords()).renderAll();
}
selectAllCanvasObjects();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.8/fabric.min.js"></script>
<canvas id="c"></canvas>
You can use below code to select all text object.
var object_length = parseInt(canvas.getObjects().length) - 1;
for(var i = 0; i <= object_length; i++)
{
canvas.setActiveObject(canvas.item(i));
var obj = canvas.getActiveObject();
var object_type = obj.type;
if(object_type == "text")
{
//Write your code here
canvas.renderAll();
}
}
canvas.deactivateAllWithDispatch();
canvas.renderAll();
After completion of execution deselect all objects so it will not show you last selected object as selected.
Related
I am non-native English speaker and I am beginner of programming language. I understand that my explanation is not best but I am trying to explain better to people to understand what I am trying to do. So, please be patient with me and please not try to down vote (it hurt my feelings) instead of tell me why my explanation is bad. I appreciate your time to read this. Thank you.
I am working on canvas game called coin sorting game which is drag the coins to the correct piggy bank images. I am stuck with if condition right now. In the current state, alert will not trigger when specific image touch to other specific image. For example, when 1yen coin image touches with 1yen piggy bank image then trigger alert otherwise no event occur.
I thought adding images to if condition will set specific images but it did not work.
if (haveIntersection(obj.getClientRect(), targetRect)&& (ichiYenImg === ichiYenpiggyImg)) {
alert("Intersection");
}
Can anyone give me an advice how to attempt this problem?
Any help is greatly appreciated!
var stage = new Konva.Stage({
width: 400,
height: 200,
container: 'container'
});
var layer = new Konva.Layer();
stage.add(layer);
layer.on('dragmove', function(e) {
var target = e.target;
var targetRect = e.target.getClientRect();
layer.children.each(function(obj) {
if (obj === target) {
return;
}
if (haveIntersection(obj.getClientRect(), targetRect)&& (ichiYenImg === ichiYenpiggyImg)) {
alert("Intersection");
}
});
});
function haveIntersection(r1, r2) {
return !(
r2.x > r1.x + r1.width/2 ||
r2.x + r2.width/2 < r1.x ||
r2.y > r1.y + r1.height/2 ||
r2.y + r2.height/2 < r1.y
);
}
// This will draw the image on the canvas.
function drawImage(source, konvaImage) {
layer.add(konvaImage);
var image = new Image();
image.src = source;
image.onload = function() {
konvaImage.image(image);
layer.draw();
}
}
//1yen
var ichiYenImg = new Konva.Image({
x: 20,
y: 20,
width: 100,
height: 100,
draggable: true
});
var sourceImg1 = "https://illustrain.com/img/work/2016/illustrain09-okane5.png";
drawImage(sourceImg1, ichiYenImg);
var goYenImg = new Konva.Image({
x: 120,
y: 20,
width: 100,
height: 100,
draggable: true
});
var sourceImg2 = "https://illustrain.com/img/work/2016/illustrain09-okane7.png";
drawImage(sourceImg2, goYenImg);
//piggy bank 1yen
var ichiYenpiggyImg = new Konva.Image({
x: 300,
y: 100,
width: 100,
height: 100,
draggable: false
});
var sourceImg7 = "https://user-images.githubusercontent.com/31402838/63416628-a322b080-c3b4-11e9-96e8-e709ace70ec1.png";
drawImage(sourceImg7, ichiYenpiggyImg);
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://unpkg.com/konva#4.0.5/konva.min.js"></script>
</head>
<body>
<div id="stage-parent">
<div id="container"></div>
</div>
</body>
</html>
Your code is mainly good - the issue is with the comparison of the objects in the 'if' statement copied below, where your intention is to decide if the user is dragging the correct value coin to the piggy bank. Comparing JavaScript objects is valid, but it can lead to unpredictable results - a more reliable & robust approach is to be more explicit, set a known attribute value on each object and compare those values.
if (haveIntersection(obj.getClientRect(), targetRect)&& (ichiYenImg === ichiYenpiggyImg)) {
alert("Intersection");
}
My answer in the code snippet is to modify the code to use the Konva 'name' variable to hold the coin and bank values. You can see I set them both to 1yen. Now in the dragMove() function I get the name attr from each of the objects being compared. When they match, we have a valid hit, and when no match the coin & bank combination are invalid.
I modified the code to put a red border around the bank when the correct coin is dragged.
See the Konva documentation for the name attr here.
var stage = new Konva.Stage({
width: 400,
height: 200,
container: 'container'
});
var layer = new Konva.Layer();
stage.add(layer);
layer.on('dragmove', function(e) {
var target = e.target;
var targetRect = e.target.getClientRect();
layer.children.each(function(obj) {
if (obj === target) {
return;
}
// capture the result of the intersection test.
var checkHit = haveIntersection(obj.getClientRect(), targetRect);
// get the objects name attribute
var nameDragged = e.target.attrs['name'];
var namePiggy = obj.attrs['name'];
// decide if they match
var checkNames = (nameDragged === namePiggy);
// finally decide if we have a valid hit
if (checkHit && checkNames) {
// hit ok !
obj.stroke('red');
obj.strokeWidth(2)
}
else {
// no hit or not matching name
obj.stroke(false);
obj.strokeWidth(0)
}
});
});
function haveIntersection(r1, r2) {
return !(
r2.x > r1.x + r1.width/2 ||
r2.x + r2.width/2 < r1.x ||
r2.y > r1.y + r1.height/2 ||
r2.y + r2.height/2 < r1.y
);
}
// This will draw the image on the canvas.
function drawImage(source, konvaImage) {
layer.add(konvaImage);
var image = new Image();
image.src = source;
image.onload = function() {
konvaImage.image(image);
layer.draw();
}
}
//1yen
var ichiYenImg = new Konva.Image({
x: 20,
y: 20,
width: 100,
height: 100,
draggable: true,
name: '1yen' // use the name attribute to indicate the coin value
});
var sourceImg1 = "https://illustrain.com/img/work/2016/illustrain09-okane5.png";
drawImage(sourceImg1, ichiYenImg);
var goYenImg = new Konva.Image({
x: 120,
y: 20,
width: 100,
height: 100,
draggable: true
});
var sourceImg2 = "https://illustrain.com/img/work/2016/illustrain09-okane7.png";
drawImage(sourceImg2, goYenImg);
//piggy bank 1yen
var ichiYenpiggyImg = new Konva.Image({
x: 300,
y: 100,
width: 100,
height: 100,
draggable: false,
name: '1yen' // use the name attribute to indicate the coin value
});
var sourceImg7 = "https://user-images.githubusercontent.com/31402838/63416628-a322b080-c3b4-11e9-96e8-e709ace70ec1.png";
drawImage(sourceImg7, ichiYenpiggyImg);
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://unpkg.com/konva#4.0.5/konva.min.js"></script>
</head>
<body>
<div id="stage-parent">
<div id="container"></div>
</div>
</body>
</html>
I'm grouping a few elements using snapSVG's group method, pushing them to an array and applying the drag method on the array elements by looping through each element.
Could you please help me in accessing the index postion of the dragged element (grps[i]) in the drag stop handler.
g1 and var g2 are the two gropus.
grps is the array that holds the two groups.
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
</head>
JavaScript
var s = Snap(800, 600);
var grps = [];
var objects = [];
var red = s.rect(50, 50, 200, 200).attr({
fill: "red"
});
var green = s.rect(60, 60, 100, 100).attr({
fill: "green"
});
var g1 = s.group(red, green);
grps.push(g1);
var red = s.rect(300, 50, 200, 200).attr({
fill: "red"
});
var green = s.rect(310, 60, 100, 100).attr({
fill: "green"
});
var g2 = s.group(red, green);
grps.push(g1, g2);
var drag_move = function(dx, dy) {
this.attr({
transform: this.data('origTransform') + (this.data('origTransform') ? "T" : "t") + [dx, dy]
});
};
var drag_start = function() {
this.data('origTransform', this.transform().local);
};
var drag_stop = function(i) {
console.log("finished dragging");
console.log(i);
};
for (i = 0; i < grps.length; i++) {
grps[i].drag(drag_move, drag_start, drag_stop);
}
JsBin Link: http://jsbin.com/tonazosicu/10/edit?js
Thanks
You can using Function.prototype.bind() to preset some parameters like below
for (i = 0; i < grps.length; i++) {
grps[i].drag(drag_move, drag_start, drag_stop.bind(null, i));
}
Then on drag_stop you can access them like below.
var drag_stop = function(index, event) {
console.log("finished dragging");
console.log(index);
console.log(event);
};
One can achieve the same thing (in lastest versions of Snap I think) with...
grps.ForEach( function( el, i ) {
el.drag(drag_move, drag_start, drag_stop.bind(null, i))
};
But ultimately you don't need to use i, if you just use 'this' in the handler in most cases, and can simply do....
grps.ForEach( function( el ) {
el.drag(drag_move, drag_start, drag_stop)
};
I am trying to get the z-index of selected object in fabric js. Is there a way to get that?
var z_index = 1;
$('#manage_index').change(function(){
var cur_value = $(this).val();
if(cur_value!='')
{
var object = canvas.getActiveObject();
if(cur_value=='up') // Means increase z-index
{
canvas.moveTo(object, z_index);
z_index = z_index + 1;
}
else if(cur_value=='back') //Means decrease z-index
{
//var temp_index = 0; // If set it to 0, it will goes into backward,
//But i am trying to implement something like below
var temp_index = canvas.get('z-index');// Get the z-index of selected object and then decrease it
canvas.moveTo(object, temp_index-1);
}
}
$(this).val('');
});
var canvas = new fabric.Canvas('a');
canvas.add(new fabric.Rect({
left:50,
top:50,
height:50,
width:50,
fill:'red'
}));
canvas.add(new fabric.Rect({
left:70,
top:70,
height:50,
width:50,
fill:'green'
}));
canvas.add(new fabric.Rect({
left:90,
top:90,
height:50,
width:50,
fill:'blue'
}));
canvas.renderAll();
function getIndex(){
var activeObj = canvas.getActiveObject();
console.log(activeObj && canvas.getObjects().indexOf(activeObj));
}
function bringToFront(){
var activeObj = canvas.getActiveObject();
activeObj && canvas.bringToFront(activeObj).discardActiveObject(activeObj).renderAll();
}
canvas {
border: 2px solid black;
}
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>
<button onclick='getIndex()'>Index</button>
<button onclick='bringToFront()'>bringToFront</button>
<canvas id="a" width="200" height="200"></canvas>
As fabric object stores in an array , you can get index using indexOf. to rearrange order you can use the bringToFront, bringForward, sendBackwards, sendToBack. And moveTo with to specified index.
I thought it was already implemented in recent Fabric.js versions but you can still extend Fabric objects prototype :
fabric.Object.prototype.getZIndex = function() {
return this.canvas.getObjects().indexOf(this);
}
I am creating multiple circle objects, each with a unique name (or id).
When I want to select an object, I have to search through all circle objects and return the right object. With many objects this is not good for the performance I guess. Is there a way to select an object by a unique attribute?
I created a simple JSFiddle to show my current workaround to get a circle Object:
https://jsfiddle.net/t47vvtec/5/
I compare every object with the attribute and if one matches it, the object will be returned. Maybe you can help me to find an easier solution.
Here is my code to get an object so far:
function getPoint(name)
{
var line_point_array = canvas.getObjects('circle');
for (var i = 0; i < line_point_array.length; i++) {
var point = line_point_array[i];
if (point.name == name) {
return point;
}
}
}
Thanks :)
You could try something like (https://jsfiddle.net/cssimsek/akbe97c5/1/):
var FabricCanvasObject = function(canvasId, attrSet) {
this.theCanvas = new fabric.Canvas(canvasId, attrSet);
this.addShape = function(shapeAttrSet) {
var newShape = this.theCanvas.add(new fabric.Circle(shapeAttrSet));
this.canvasElements.length += 1;
this.canvasElements[shapeAttrSet.name + this.canvasElements.length] = newShape;
};
this.canvasElements = { length: 0 };
};
var myFabric = new FabricCanvasObject('c', {
targetFindTolerance: 15
});
console.log(myFabric);
myFabric.addShape({
radius: 20,
fill: 'green',
left: 100,
top: 100,
name: 'circle',
id: 1
});
myFabric.addShape({
radius: 20,
fill: 'red',
left: 150,
top: 150,
name: 'circle',
id: 2
});
myFabric.addShape({
radius: 20,
fill: 'blue',
left: 200,
top: 200,
name: 'circle',
id: 3
});
console.log(myFabric.canvasElements);
console.log(myFabric.canvasElements.circle1);
I'm trying to implement two surfaces, connected with a spring, that would react to drag in famo.us. So far I have setup the surfaces, can drag those, have a spring that interacts during the loading of the page, but not on drag. So the questions are a) how should I connect two surfaces with a spring and b) how do I update the physics when I drag one surface so that the other surface would follow the dragged surface?
The code I so far have is this
define(function(require) {
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var StateModifier = require('famous/modifiers/StateModifier');
var PhysicsEngine = require('famous/physics/PhysicsEngine');
var Circle = require('famous/physics/bodies/Circle');
var Draggable = require('famous/modifiers/Draggable');
var Spring = require('famous/physics/forces/Spring');
var Vector = require('famous/math/Vector');
var context = Engine.createContext();
var physicsEngine = new PhysicsEngine();
var ball = new Surface ({
size: [100,100],
properties: {
backgroundColor: 'red',
borderRadius: '50px'
}
});
var ball2 = new Surface ({
size: [100,100],
properties: {
backgroundColor: 'blue',
borderRadius: '50px'
}
});
var draggable = new Draggable();
var draggable2 = new Draggable();
ball.state = new StateModifier({origin:[0.2,0.2]});
ball2.state = new StateModifier({origin:[0.3,0.3]});
ball.particle = new Circle({radius:100});
ball2.particle = new Circle({radius:100});
var spring = new Spring({
anchor: ball.particle,
period: 400, // <= Play with these values :-)
dampingRatio: 0.07, // <=
length: 50
});
// var spring2 = new Spring({anchor: ball2.particle});
// physicsEngine.attach(spring, ball2.particle);
// physicsEngine.attach(spring2, ball.particle);
draggable.subscribe(ball);
draggable2.subscribe(ball2);
draggable.on('update', function() {
console.info('update');
ball2.particle.applyForce(new Vector(0, 0, -0.005 * 100));
// ball.state.setTransform(ball.particle.getTransform())
// ball.state.setTransform(ball.particle.getTransform())
// ball.particle.setVelocity([0.001,0,0]);
// physicsEngine.wake();
// physicsEngine.step();
});
draggable2.on('update', function() {
// ball2.particle.setVelocity([0.001,0,0]);
// console.info('update');
// physicsEngine.wake();
// physicsEngine.step();
});
physicsEngine.attach(spring, ball2.particle);
// spring.applyForce(ball.particle);
physicsEngine.addBody(ball.particle);
physicsEngine.addBody(ball2.particle);
// ball.on("click",function(){
// ball.particle.setVelocity([10,0,0]);
// });
//
// ball2.on("click",function(){
// ball2.particle.setVelocity([0,10,0]);
// });
context.add(draggable).add(ball.state).add(ball);
context.add(draggable2).add(ball2.state).add(ball2);
Engine.on('prerender', function(){
ball.state.setTransform(ball.particle.getTransform());
ball2.state.setTransform(ball2.particle.getTransform());
});
});
It seems like you have a pretty good understanding of the PE thus far. I can still see a few places you can improve. Here is a working example of dragging with a spring attached. Although this implementation is not perfect yet, it should get you started.. If you start with dragging the red circle, everything works as expected.. Draggable has its own position, and so does particle. So when you grab the blue circle, there remains an offset in particle. Here is what will get you 95%..
Hope it helps..
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var Transform = require('famous/core/Transform');
var Modifier = require('famous/core/Modifier');
var Draggable = require('famous/modifiers/Draggable');
var PhysicsEngine = require('famous/physics/PhysicsEngine');
var Circle = require('famous/physics/bodies/Circle');
var Spring = require('famous/physics/forces/Spring');
var context = Engine.createContext();
var physicsEngine = new PhysicsEngine();
var ball = new Surface ({
size: [100,100],
properties: {
backgroundColor: 'red',
borderRadius: '50px'
}
});
var ball2 = new Surface ({
size: [100,100],
properties: {
backgroundColor: 'blue',
borderRadius: '50px',
}
});
ball.mod = new Modifier({origin:[0.5,0.5]});
ball.draggable = new Draggable();
ball.pipe(ball.draggable);
ball.particle = new Circle({radius:100});
ball.mod.transformFrom(function(){ return Transform.translate(0,0,0) });
ball.spring = new Spring({
anchor: ball.particle,
period: 400,
dampingRatio: 0.07,
length: 50
});
ball2.mod = new Modifier({origin:[0.5,0.5]});
ball2.draggable = new Draggable();
ball2.pipe(ball2.draggable);
ball2.particle = new Circle({radius:100});
ball2.mod.transformFrom(function(){ return ball2.particle.getTransform()});
ball2.spring = new Spring({
anchor: ball2.particle,
period: 400,
dampingRatio: 0.07,
length: 50
});
ball.draggable.on('start',function(){
ball2.setProperties({pointerEvents:'none'});
if (ball2.springID) physicsEngine.detach(ball2.springID);
if (ball.springID) physicsEngine.detach(ball.springID);
ball.springID = physicsEngine.attach(ball.spring, ball2.particle);
ball2.springID = null;
ball.mod.transformFrom(function(){ return Transform.translate(0,0,0) });
ball2.mod.transformFrom(function(){ return ball2.particle.getTransform()});
})
ball.draggable.on('update', function() {
pos = ball.draggable.getPosition();
ball.particle.setPosition(pos);
});
ball.draggable.on('end', function() {
ball2.setProperties({pointerEvents:'all'});
});
ball2.draggable.on('start',function(){
ball.setProperties({pointerEvents:'none'});
if (ball2.springID) physicsEngine.detach(ball2.springID);
if (ball.springID) physicsEngine.detach(ball.springID);
ball2.springID = physicsEngine.attach(ball2.spring, ball.particle);
ball.springID = null;
ball2.mod.transformFrom(function(){ return Transform.translate(0,0,0) });
ball.mod.transformFrom(function(){ return ball.particle.getTransform()});
})
ball2.draggable.on('update', function() {
pos = ball2.draggable.getPosition();
ball2.particle.setPosition(pos);
});
ball2.draggable.on('end', function() {
ball.setProperties({pointerEvents:'all'});
});
ball.springID = physicsEngine.attach(ball.spring, ball2.particle);
physicsEngine.addBody(ball.particle);
physicsEngine.addBody(ball2.particle);
context.add(ball.mod).add(ball.draggable).add(ball);
context.add(ball2.mod).add(ball2.draggable).add(ball2);