I hope you can help. I'm having some trouble programmatically resizing a Group of Fabric JS objects. I add the objects to the canvas using canvas.add(object) and then add them to the group. However when trying to resize the objects as a group, the usual setHeight(), scale() and scaleToWidth/Height() methods seem to have no effect.
My code is in several places, but the essence is:
var obj = ........ // I Get my obj from an SVG path
var objectGroup = new fabric.Group();
canvas.clipTo = function(ctx) {
obj.render(ctx);
}
objectGroup.add(obj);
I also tried objectGroup.addWithUpdate(obj);
Then, after adding more objects to the group; in my resize event, I work out the scale I need and do:
objectGroup.scaleToWidth(newX);
objectGroup.scaleToHeight(newY);
objectGroup.setCoords();
canvas.renderAll();
Am I missing something?? Do I have to add my obj to the canvas as well as rendering it inside the clipTo function?
Thanks in advance :)
Related
I recently started to work with fabricjs, and I have a question about groups. I would like to center all objects (many) when canvas is resized. So I tought to build a group with all objects in my canvas and center it.
However, in order to do that, I have to:
retrieve all objects
add them to my group
remove them from my canvas
add the group to my canvas
A complex process, and, above all, my objects lost the possibility to be manipulate individually.
I am wondering if it is possible to manipulate a group without add it in my canvas?
This code should work with fabric 2.0 beta.
A similar code is possible for the version 1.7.x and you can create from this using the activeGroup logic.
What you may want to do is:
// After the canvas resize:
// get all Objects:
var objects = canvas.getObjects();
// create a multiselection
var selection = new fabric.ActiveSelection(objects, { canvas: canvas });
// now get size of this selection:
var width = selection.width;
var height = selection.height;
// scale the selection accordingly
var scale = ( find the right scale value, probably canvas.width/width or canvas.height/height. The biggest or smaller of them )
selection.scale(scale);
// center the selection in the canvas
selection.center();
// destroy the selection
selection.destroy();
And this should be working.
Do you need the group? Or you are just creating them to center the objects? If not, you can use object.center() for each one of the canvas object you want to center in screen.
canvas.forEachObject(function (o) {
o.center();
});
Apologies if this has been answered before, I think I maybe searching for the wrong keywords.
I have an element rendered on the canvas from another library.
Every time stage.update() gets called all my createJS elements get rendered on top.
The element however needs to sit between different createjs objects.
So either I need to find a way to turn this element into a createJs DisplayElement to put it in the correct index position.
Or I need to update just a Container and not the whole stage.
Can someone point me into the right direction?
Thanks
The best approach for this is to render your non-EaselJS content onto another Canvas, and then use it as the source for a Bitmap.
// Non-EaselJS content (whatever you can imagine!)
var canvas1 = document.getElementById("non-easel-canvas");
var context = canvas1.getContext("2d");
context.doStuffWithCanvasAPIs();
// EaselJS content (red background, blue circle)
var stage = new createjs.Stage("easel-canvas");
var bottom = new createjs.Shape();
bottom.graphics.beginFill("red").drawRect(0,0,800,600);
var top = new createjs.Shape();
top.graphics.beginFill("blue").drawCircle(0,0,25);
top.x = top.y = 100;
// Non-easel content added to Easel
var bmp = new createjs.Bitmap(canvas1);
stage.addChild(bottom, bmp, top);
stage.update();
Hope that makes sense. You can also the reverse, and draw the EaselJS content into a non-EaselJS stage using drawImage, and passing the EaselJS canvas as the source. This is how you can mix EaselJS content into things like three.js.
Note that you can also draw any EaselJS content directly without a stage. Each display object (including Container) has a draw() method, which you can call, which draws the object into a supplied context.
http://www.createjs.com/docs/easeljs/classes/DisplayObject.html#method_draw
Cheers,
You have two options here:
Do not use the other library at all, but EaselJS only.
...or...
Use multiple canvases.
Since you need to stack this graphics object in between two easeljs objects, you would need three canvases to accomplish what you're trying to do, and two easeljs stages. Still, this is a hacky workaround for a weird problem.
I am beginning to explore the HTML5 canvas, and I apologize in advance for the naivety of my question. Using Flash CC, I have generated a canvas with a rectangle on it:
(function (lib, img, cjs, ss) {
var p; // shortcut to reference prototypes
// library properties:
lib.properties = {
width: 550,
height: 400,
fps: 24,
color: "#FFFFFF",
manifest: []
};
// symbols:
// stage content:
(lib.canvas_test = function() {
this.initialize();
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.beginFill().beginStroke("#669966")
.setStrokeStyle(1,1,1).moveTo(-94,-62).lineTo(94,-62).lineTo(94,62).lineTo(-94,62).closePath();
this.shape.setTransform(198,136);
this.shape_1 = new cjs.Shape();
this.shape_1.graphics.beginFill("#FF933C")
.beginStroke().moveTo(-94,62).lineTo(-94,-62).lineTo(94,-62).lineTo(94,62).closePath();
this.shape_1.setTransform(198,136);
this.addChild(this.shape_1,this.shape);
}).prototype = p = new cjs.Container();
p.nominalBounds = new cjs.Rectangle(378,273,190,126);
})(lib = lib||{}, images = images||{}, createjs = createjs||{}, ss = ss||{});
var lib, images, createjs, ss;
Now I am stuck. How can I retrieve (and change) the color of the rectangle using a Javascript function? I had hoped that the shapes would simply be children of the canvas, but this does not seem to be the case.
The earlier answers are correct about Canvas being basically a bitmap, but EaselJS gives you a retained graphics mode, so you can change properties and update the stage/canvas to reflect them.
You are using Flash export to generate your content, so you should be able to access your elements via the exportRoot, which is created in the HTML. This is essentially the Flash "stage", represented by an EaselJS container that is defined by canvas_test in your exported library.
exportRoot = new lib.canvas_test();
You can see in the canvas_test code, each "child" is defined. Any graphics are wrapped in EaselJS Shape instances. There are also classes for handling groups (Containers), Bitmaps, Text, and animations (MovieClips).
Here is your exported code above put added to the stage:
http://jsfiddle.net/lannymcnie/b5me4xa2/
It is easy to modify shapes once they are created, but you have to define them with that in mind. The Flash export doesn't really provide you this capability, since it just exports everything as a single, chained graphics instructions list. You can however introspect it fairly easily to find the commands you want to modify. Warning: This requires EaselJS 0.7.0+ in order to work. Earlier versions will not work with this approach
The demo you provided has a single Rectangle. Unfortunately there is a bug in the current version of Flash that exports it as 2 shapes, one for the stroke, and another for the fill. This example will modify the stroke.
var shape = exportRoot.shape; // Access the shape instance that has the stroke
var stroke = shape.graphics._stroke;
stroke.style = "#ff0000"; // Set to red.
To do the fill, you can do the same thing on shape_1, but affect the _fill instead. Here is an updated sample
You can also access any of the instructions, and affect their properties. You can see a full command list in the Graphics docs (see the sidebar for the full list). Here is a quick sample modifying the first moveTo command on the stroke:
var shape = exportRoot.shape;
shape.graphics._activeInstructions[0].x = -110;
You can see a sample of that code here: http://jsfiddle.net/lannymcnie/b5me4xa2/2/ -- You will have to modify both fill and stroke to move them both :)
Canvas is basically a bitmap, it has no children. An SVG works more like you're imagining but a canvas just has pixels. If you want to change a canvas you're either going to have to go through it and find the pixels, or create a javascript object representing your drawing object (the rectangle), keep it separate from your canvas background, and redraw the the background and object when there are any changes.
[Added]
I'm not familiar with Flash CC, but as pointed out in the comment, perhaps there is some capability there already to do what the commenter and myself are describing - I'm afraid I don't know.
I'm trying to use snap.svg library to rotate and move my object but I am getting this weird behavior where the object gets morphed.
http://codepen.io/anon/pen/vOwRga
var s = Snap.select("#svg");
var rect1 = s.select("#rect1");
var rect2 = s.select("#rect2");
var rotateMatrix = new Snap.Matrix();
rotateMatrix.rotate(180,302,495);
this.spin = function() {
rect1.animate({transform:'r180,302,160'},5000,function(){
rect1.animate({transform:'r0,302,160'},5000);
});
rect2.animate({transform: rotateMatrix},5000,function(){
rect2.animate({transform: rotateMatrix.invert},5000);
});
}
So here I'm rotating two different rectangles. First one works fine and the second one is where i try to use matrix.
What am I doing wrong? Why is this happening? what is the meaning of life?
In the first one, you are animating a rotation. Snap knows it is a rotation because of the way you have defined it with Snap's special 'r' initialiser.
In the second one you are just passing a matrix that describes a transform from one orientation to another. Snap, and the browser, have no idea that it represents a rotation. So all it is doing is interpolating the values in the matrix.
I am trying to add handles (handleIn, handleOut) to the segments created in Paper.js using a mousetool like the following:
var myPath = new Path();
myPath.strokeColor = 'black';
function onMouseDown(event) {
myPath.add(event.point);
}
At the end of drawing, I close the polygon, and that is when I would like the handles to be generated. Ideally there is a function or settings that would add the missing handles, but if not, any help pointing me in the right direction for how to calculate the handle positions would be greatly appreciated. I don't want to use smooth() or simplify() since I want the original shape of the polygon to remain. I just want to have handles so that I can add subtle curves to specific line segments if necessary.
Handles can be set using segment.handleIn and segments.handleOut properties.
Handles are stored relative to the segment point, you just have to make sure they are of the length you want. You can then modify them like any other vector/point.
simple demo