Adding id and custom attribute in fabric js - fabricjs

I am new to fabtric js. How can I add auto generating id and custom attribute to fabric js object.
For example, I would like to add an id that is autogenerated with increment integer of type of object and category: 'new' when an object is added
As far as I am concerned, fabric js does not support this by default.
var text = new fabric.IText('Enter text here', {
id: 'text-i' -> where i increment according to number of IText in the canvas
left: 150,
top: 50,
type: 'new'
});

one way you can achive this is set some extra object in your canvas:
canvas.ObjectCounter = {};
then add all the tipes to it:
canvas.ObjectCounter.['text'] = 0;
canvas.ObjectCounter.['rect'] = 0;
canvas.ObjectCounter.['i-text'] = 0;
and so on...
when creating object:
var text = new fabric.IText('Enter text here', {
id: 'text-' + canvas.objectCounter['i-text']++,
left: 150,
top: 50
});
be aware that 'type' is a property that needs to stay as it is, do not change it.
This will be just number of objects created if you handle like this.
If you want to know how many of them are on the canvas you have to use something different in the events
canvas.on('object:added', function(e){});
canvas.on('object:removed', function(e){});

Related

fabric js how to use globalCompositeOperation in groups

I am trying to create groupe using fabricjs
var group = new fabric.Group(
[ circle, this.callerObject ],
{globalCompositeOperation:'xor'}
);
console.log(group);
this.mainCanvas.add(group);
But which globalCompositeOperation I have not set it is not working it always give the same result. I can make it using clear canvas, but I want to know, can I do it using native fabricjs methods?
I find solution myself)) to make it work need add globalCompositeOperation to the second object.
this.callerObject.set('globalCompositeOperation','xor');
var group = new fabric.Group(
[ circle, this.callerObject ]
);
But it have new problem)) this is work across all images)
To solve problem with cross showing
I have convert group to dataUrl, and to save state of object create new group, with object and image from previous group.
createXorGroup: function(object){
var self = this;
var baseStateTop = this.callerObject.top;
var baseStateLeft = this.callerObject.left;
this.callerObject.set('globalCompositeOperation','xor');
this.callerObject.set('active', false);
var group = new fabric.Group([ object, this.callerObject ]);
fabric.Image.fromURL(
group.toDataURL(),
function(image){
image.setOriginToCenter && image.setOriginToCenter();
self.callerObject.set('globalCompositeOperation','source-over');
self.callerObject.set('opacity', 0);
group = new fabric.Group([ self.callerObject, image ]);
self.mainCanvas.add(group);
group.setOriginToCenter && group.setOriginToCenter();
group.set('top', baseStateTop).set('left', baseStateLeft).setCoords();
group.setCenterToOrigin && group.setCenterToOrigin();
self.mainCanvas.remove(self.callerObject);
group.inCircle = true;
group.set('active', true);
},
{
originX: 'center',
originY: 'center',
top: this.callerObject.top,
left: this.callerObject.left
}
);
}
It is not native fabricjs object, I have override some properties for my work, but I hope you understand the main aim and it will be helpful
Continue to work with this library
To make xor to svg I have write this:
setGlobalCompositeOperation: function(object, type){
if(object.imageType == 'svg'){
for (var i = 0; i < object.paths.length; i++) {
this.setGlobalCompositeOperation(object.paths[i], type);
}
}else{
object.set('globalCompositeOperation', type);
}
}
But this do not work for text in mozila 31.6.0(( I'm looking solution for text

Famo.us RenderController not working under SequentialLayout?

I have added a common Surface and a Scrollview (actually a FlexScrollView) to a SequentialLayout and then added the layout to my View as the following code shows:
function _createCameraView() {
var layoutViews = [];
this.cameraView = new View({
size: [undefined, this.options.footerSize]
});
var layout = new SequentialLayout({
size: [undefined, this.options.footerSize],
direction: Utility.Direction.Y
});
var backgroundSurface = new Surface({
size: [undefined, 120],
content: 'some content',
classes : ['photo-guide-content'],
properties: {
backgroundColor: 'transparent',
zIndex: 4
}
});
// detail list
var detailsList = new FlexScrollView({
layout: ListLayout,
direction: Utility.Direction.X, // set direction to horizontal
paginated: true,
//autoPipeEvents: true,
useContainer: true,
container : {
size: [undefined, 60],
properties : {
'z-index' : 5,
}
}
});
layoutViews.push(backgroundSurface);
layoutViews.push(detailsList);
layout.sequenceFrom(layoutViews);
this.cameraView.add(alignModifier).add(layout);
}
Then I've added a RenderController on another view and I'm using it to display my cameraView like this:
function _selectCamera() {
if (!this.cameraView) {
_createCameraView.call(this);
}
this.footerRender.hide(this.mapView);
this.footerRender.show(this.cameraView);
}
I know I don't need to call the hide method from the render on the function above, just the show method and it should swap the views with a smooth opacity transition, which is defined by default. Although when using this Sequential Layout I'm not getting this effect. I know it has to do with this layout because I've tried to switch the layout to a FlexibleLayout and a GridLayout, and it works fine with these two. So, my question is, why doesn't work with the SequentialLayout? I've also noticed it has a method called setOutputFunction(outputFunction), is there a way to use it so the layout uses the opacity returned from the RenderController or how can it be fixed some other way?
Try adding a getSize method to your view.
Something like this:
this.cameraView.getSize = function() {
return [undefined, undefined];
};

How I can combine the text properties in a variable for using globally?

How I can combine the text properties in a variable for using globally?
Thanks you in advance for helping !
var text = game.add.text(game.world.centerX, game.world.centerY + 50, 'Challenge your friends!');
text.font = 'Arial'; // here it is the property of phaser
text.fontSize = '12px'; // here it is the property of phaser
text.align = 'center'; // here it is the property of phaser
text.fontWeight = 'bold'; // here it is the property of phaser
If I understand your question, you just need to take advantage of the style object that the text constructor takes. See http://docs.phaser.io/Phaser.Text.html#Text
You can create a global variable somewhere, for example:
GLOBAL_TEXTSTYLE = {font : '12px Arial', font-weight: 'bold', align: 'center' };
And then use it in function calls:
var text = game.add.text(game.world.centerX, game.world.centerY + 50,
'Challenge your friends!', GLOBAL_TEXTSTYLE);
Some people store things like this within a property of the game object. You risk having name collisions with game's other properties, but you could do this via:
// Create an object to store my game variables
game.myGlobals = {};
game.myGlobals.textStyle = {font:'12px Arial', font-weight:'bold', align:'center' };
Then use it:
var text = game.add.text(game.world.centerX, game.world.centerY + 50,
'Challenge your friends!', game.myGlobals.textStyle);

Drag and zoom text with Kineticjs

I am trying to zoom and pan a text which is draggable already. All the examples are on images or shapes and it seems I cannot adapt it to a text object. My questions are:
Do I have to use the anchors or is any simpler way zoom a text with Kineticjs?
I found an example regarding zooming a shape and the code crashes here:
var layer = new Kinetic.Layer({
drawFunc : drawTriangle //drawTriangle is a function defined already
});
Can we call a function while we are creating a layer?
I usually create a layer and then add the outcome of the function in it.
Any idea would be great, thanks.
I thought of many ways you could do this but this is the one I ended up implementing: jsfiddle
Basically, you have an anchor (which doesn't always have to be there, you can hide and show it if you would like. Let me know if you need help with that) and if you drag the anchor down it increases the fontSize, and if you drag the anchor up it decreases the fontSize.
I followed the exact same anchor tutorial but instead I added a dragBoundFunc to limit dragging to the Y-axis:
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
};
}
});
And then I updated the updateAnchor() function to only detect the single anchor I added to the group named sizeAnchor:
var mY = 0;
function update(activeAnchor, event) {
var group = activeAnchor.getParent();
var sizeAnchor = group.get('.sizeAnchor')[0];
var text = group.get('.text')[0];
if (event.pageY < mY) {
text.setFontSize(text.getFontSize()-1);
} else {
text.setFontSize(text.getFontSize()+1);
}
sizeAnchor.setPosition(-10, 0);
mY = event.pageY;
}
Basically mY is used compared to the e.PageY to see if the mouse is moving up or down. Once we can determine the mouse direction, then we can decide if we should increase or decrease the fontSize!
Alternatively, you can use the mousewheel to do the exact same thing! I didn't implement it myself but it's definitely doable. Something like:
Mousewheel down and the fontSize decreases
Mousewheel up and the fontSize increases
Hopefully this emulates "Zooming" a text for you. And I guess being able to drag the text acts as "panning" right?
UPDATE (based on comment below)
This is how you would limit dragging to the Y-Axis using dragBoundFunc:
var textGroup = new Kinetic.Group({
x: 100,
y: 100,
draggable: true,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
};
}
});
See the updated jsfiddle (same jsfiddle as above)

How to update a feature in an Openlayers.Layer?

i have an xml file with coordinates in it and i want to draw a line of those points on an Openlayers Map. I already have a Openlayers.Layer.Vector and i am creating a feature as follows:
var points = [];
for (var i = 0; i < coords.length; i++)
{
point = new OpenLayers.Geometry.Point(aPointsArray[i].lon, aPointsArray[i].lat);
points.push(point);
}
var geometry = new OpenLayers.Geometry.LineString(points);
var feature = new OpenLayers.Feature.Vector(geometry, null,
{
strokeColor: aColor,
strokeOpacity: 0.7,
strokeWidth: 3
});
aLayer.addFeatures([feature]);
This works a expected and i am seeing a line on my map. The problem is now, that the points i get from the .xml are changed dynamically by another program and I want to draw those changes live on my map. I already have a method that updates the maps periodically but how do i update the feature/geometry to the new points ?
Try aLayer.drawFeature(yourChangedFeature);

Resources