It's ok to add event ability to a constructor:
function Stream() {
events.EventEmitter.call(this);
}
util.inherits(Stream, events.EventEmitter);
But how to add event ability to an object instance? The following code doesn't work:
var foo = {x: 1, y: 2};
util.inherits(foo, event.EventEmitter);
events.EventEmitter.call(foo);
After running the above code, foo.on still be undefined.
Is there a way to inherit or mix-in EventEmitter's content?
You can use the npm module node.extend.
It is a port of jQuery's $.extend and with it, you can do this:
var extend = require('node.extend'),
events = require('events');
extend(foo, events.EventEmitter.prototype);
or, if you don't want to use another module, you can use this:
function extend(target) {
var sources = Array.prototype.slice.call(arguments, 1);
return sources.forEach(function (source) {
Object.keys(source).forEach(function (key) {
target[key] = source[key];
});
}), target;
}
var events = require('events');
var foo = {x: 1, y: 2};
extend(foo, events.EventEmitter.prototype);
Related
i wonder to know is the code below runs right
a.js:
var obj = {
name: 'a'
};
module.exports = obj;
b.js
var b = require('./a');
module.exports = b;
c.js
var a = require('./a');
console.log(a); // {name: 'a'}
a.name = 'b';
console.log(require('./a')); // {name: 'b'}
console.log(require('./b')); // {name: 'b'}
so, i can change a module exports from outside
if i cange the a.js to a.json
a.json
{
"name": "a"
}
i got the same result
how can i export a module can't modify or override form outside
You can freeze an object:
// in order for people to not add properties through the prototype
var o = Object.create(null);
o.name = 'a';
Object.freeze(o); // no one can change properties
Object.seal(o); // no one can add properties;
module.exports = o;
If you're using a modern version of nodejs (read io.js) you can also use a proxy:
var o = {name: 'a'};
var p = new Proxy(o, {
set: function(obj, prop, value) {
// unlike the freeze approach, this also throws in loose mode
throw new TypeError("Can't set anything on this object");
}
});
return p;
That said, who are you guarding against? Why would people change the object in another module?
See example below. I am trying to trigger an event on a.
var events = require("events");
function foo() {
this.on("ping", function() {
console.log("bar!");
})
}
foo.prototype = new events.EventEmitter();
var a = new foo();
var b = new foo();
a.emit("ping");
This prints "bar!" two times, so I am assuming I am adding the event listener on "all" the functions, not the specific instance. Since I am running foo two times, I am adding two event listeners, nothing strange really, althought not so intuitive.
Is there a way to add the event listener only on a?
(Please edit this question if I am using the wrong terminology, used to class-based programming)
edit: So I suspect it is because I am using the same event emitter as prototype.. But in that case, how can I create one for each new foo()?
Typically you inherit (from EventEmitter) like this:
var inherits = require('util').inherits,
EventEmitter = require('events').EventEmitter;
function Foo() {
if (!(this instanceof Foo))
return new Foo();
EventEmitter.call(this);
this.on('ping', function() {
console.log('bar!');
});
}
inherits(Foo, EventEmitter);
// add Foo-specific prototype functions *after* `inherits()`
Foo.prototype.myfunc = function(a, b) {
return a + b;
});
var a = new Foo();
var b = new Foo();
a.emit('ping');
This is the setup that most modules on npm and objects in node core use to inherit from another object.
I am trying to perform a special action whenever the user double clicks any object located inside the canvas. I have read the docs and not found any mouse:dblclick-like event in the documentation. I tried doing something like:
fabric.util.addListener(fabric.document, 'dblclick', callback);
Which does trigger the dblclick event but does not give specific information about the actual object that is being clicked on the canvas.
Any ideas of the most FabricJS-y way of doing this?
The more elegant way is to override fabric.Canvas._initEventListeners to add the dblclick support
_initEventListeners: function() {
var self = this;
self.callSuper('_initEventListeners');
addListener(self.upperCanvasEl, 'dblclick', self._onDoubleClick);
}
_onDoubleClick: function(e) {
var self = this;
var target = self.findTarget(e);
self.fire('mouse:dblclick', {
target: target,
e: e
});
if (target && !self.isDrawingMode) {
// To unify the behavior, the object's double click event does not fire on drawing mode.
target.fire('object:dblclick', {
e: e
});
}
}
I've also developed a library to implement more events missed in fabricjs : https://github.com/mazong1123/fabric.ext
This is similar to #LeoCreer's answer but actually gets access to the targeted object
fabric.util.addListener(canvas.upperCanvasEl, 'dblclick', function (e) {
var target = canvas.findTarget(e);
});
The Correct way to add custom events to Fabric.js
window.fabric.util.addListener(canvas.upperCanvasEl, 'dblclick', function (event, self) {
yourFunction(event);
});
or use fabric.ext
I'm using this workaround:
var timer = 0;
canvas.item(0).on('mouseup', function() {
var d = new Date();
timer = d.getTime();
});
canvas.item(0).on('mousedown', function() {
var d = new Date();
if ((d.getTime() - timer) < 300) {
console.log('double click')
}
});
Here is a quick and easy way to add a double click event handler to Fabric JS -
Include following code snippet to your html file. Just ensure this is loaded after the main fabric.js library
<script type="text/javascript">
fabric = (function(f) { var nativeOn = f.on; var dblClickSubscribers = []; var nativeCanvas = f.Canvas; f.Canvas = (function(domId, options) { var canvasDomElement = document.getElementById(domId); var c = new nativeCanvas(domId, options); c.dblclick = function(handler) { dblClickSubscribers.push(handler) }; canvasDomElement.nextSibling.ondblclick = function(ev){ for(var i = 0; i < dblClickSubscribers.length; i++) { console.log(ev); dblClickSubscribers[i]({ e :ev }); } }; return c; }); return f; }(fabric));
</script>
Then add this code to listen a double click event:
canvas.dblclick(function(e) {
});
To get information about the actual object that is being clicked on the canvas, use following method -
canvas.getActiveObject();
eg.
canvas.dblclick(function(e) {
activeObject = canvas.getActiveObject();
});
I am late but now fabricjs has mousedblclick event.
Listed at: http://fabricjs.com/docs/fabric.Object.html
See all events:
http://fabricjs.com/events
I suddenly realized that event emitter in NodeJS is usually like a static method in Java.. Example:
// This illustrated that event listener is universal
function A(a){
var that = this;
this.a = a;
this.cnt = 0;
this.done = function(){
this.emit("done");
};
this.say = function(){
console.log(a + " = " + that.cnt);
};
this.inc = function(){
that.cnt++;
};
}
A.prototype = new events.EventEmitter;
var a = new A("a"),
b = new A("b"),
c = new A("c");
a.on("done",function(){a.inc()});
b.on("done",function(){b.inc()});
c.on("done",function(){c.inc()});
c.done();
c.done();
a.say();
b.say();
This code would give output:
a = 2
b = 2
While I'm actually expecting:
a = 0
b = 0
I believe this is because of the line:
A.prototype = new events.EventEmitter;
and I think the "prototype" kind of definition would be used like "static" in Java.
In order to have per-object based event listener, I changed the above code to be:
function B(a){
var that = this;
this.evt = new events.EventEmitter;
this.a = a;
this.cnt = 0;
this.done = function(){
this.evt.emit("done");
};
this.say = function(){
console.log(a + " = " + that.cnt);
};
this.inc = function(){
that.cnt++;
};
}
var a = new B("a"),
b = new B("b"),
c = new B("c");
a.evt.on("done",function(){a.inc()});
b.evt.on("done",function(){b.inc()});
c.evt.on("done",function(){c.inc()});
c.done();
c.done();
a.say();
b.say();
This would be per-object event listener, but I don't really think that is a good design/implementation because it breaks the chaining of EventEmitter. I.e., like code bellow:
// can chain another method of A after the on() method
a.on("event",functionCallback).anotherMethodOfA();
I'd like to ask, what's a proper implementation of the per-object event listener in NodeJS?
You can use addListener or on to attach listeners to your custom events. You won't need to chain calls on these methods. Of course you can inherit any object from EventEmitter and add emitting functionality to your object. You can inherit your object from an instance of EventEmitter. There's is function called inherit in the util library which does that for you.
var util = require('util');
var eventEmitter = require('events').EventEmitter;
// Now create your constructor/object.
function MyObj(a, b) {
this.a = a;
this.b = b;
.
.
.
}
util.inherits(MyObj,eventEmitter);
// Implement your methods and add the functionality you need.
MyObj.prototype.aMethod = function(arg) {
.
.
.
// Define how to emit events
if (arg == 'A')
this.emit('eventA', this.a);
else if (arg == 'B')
this.emit('eventB');
// Return this for chaining method calls
return this;
}
MyObj.prototype.anotherMethod = function() {
// Add more functionality...
.
.
.
return this;
}
// Now instantiate the constructor and add listenters
var instanceOfMyObj = new MyObj('a parameter', 'another parameter');
instanceOfMyObj.on('eventA', function(a){
// Handle the event
});
// Now chain calls..
instanceOfMyObj.aMethod('A').anotherMethod(); // This will trigger eventA...
I have inherited a class from another JS, and added few prototype function over Parent functions. When i create a new instance of child, i want to call the constructor of parent. Please suggest a way.
Parent
function Parent() { .. }
Parent.prototype.fn1 = function(){};
exports.create = function() {
return (new Parent());
};
Child
var parent = require('parent');
Child.prototype = frisby.create();
function Child() { .. }
Child.prototype.fn2 = function(){};
exports.create = function() {
return (new Child());
};
You can use module util. Look simple example:
var util = require('util');
function Parent(foo) {
console.log('Constructor: -> foo: ' + foo);
}
Parent.prototype.init = function (bar) {
console.log('Init: Parent -> bar: ' + bar);
};
function Child(foo) {
Child.super_.apply(this, arguments);
console.log('Constructor: Child');
}
util.inherits(Child, Parent);
Child.prototype.init = function () {
Child.super_.prototype.init.apply(this, arguments);
console.log('Init: Child');
};
var ch = new Child('it`s foo!');
ch.init('it`s init!');
First of all, do not export create method, export constructor (Child, Parent). Then you will be able to call parent's constructor on child:
var c = new Child;
Parent.apply(c);
About inheritance. In node you can use util.inherits method, which will setup inheritance and setup link to superclass. If you don't need link to superclass or just want to inherit manually, use proto:
Child.prototype.__proto__ = Parent.prototype;
Parent (parent.js)
function Parent() {
}
Parent.prototype.fn1 = function() {}
exports.Parent = Parent;
Child
var Parent = require('parent').Parent,
util = require('util');
function Child() {
Parent.constructor.apply(this);
}
util.inherits(Child, Parent);
Child.prototype.fn2 = function() {}