In Fabric.js we have Object modified events like object:modified. Do we have similar event for the entire canvas.
Actually I am trying to implement undo and redo features. I am saving the canvas as JSON if something happens on it and loading it again for undo feature.
Do we have any better solution for this features in Fabric.js?
Don't forget to check for added/removed objects too. You could implement it like this:
var canvasModifiedCallback = function() {
console.log('canvas modified!');
};
canvas.on('object:added', canvasModifiedCallback);
canvas.on('object:removed', canvasModifiedCallback);
canvas.on('object:modified', canvasModifiedCallback);
This is better explained in this link. Use it this way:
canvas.on('object:moving', function(e) { // or 'object:added'
var activeObject = e.target;
console.log(activeObject.get('left'), activeObject.get('top'));
});
Related
I am using the Alloy Diagram Builder to create and display network topology.
I would like to remove default click and drag events attached to each nodes, so viewers would not have the ability "build" diagrams but only view diagrams that I have generated.
http://alloyui.com/examples/diagram-builder/real-world/
I have tried these but it does not work.
// detach click event to all nodes with class aui-diagram-node.
Y.all('.aui-diagram-node').detach("click");
// unbind
$(".aui-diagram-node").each(function(){
$(this).unbind();
});
I believe the event is attached to the container .aui-diagram-builder-drop-container via delegate() and the event would be mousedown.
Merely by accident I found a hack that might work for this. I was adding tooltips to my page on which I had a diagram builder, well apparently the tooltips layer a div over the page and simply set the opacity on it to be clear and the object still resides. After a tooltip had come up i was unable to interact with the piece of the diagram builder the tooltip had popped up over.
So based of this concept, why not try overlaying a div over the entire canvas of the diagram and give it a high z-index so that it sits on top. It should effectively not allow interaction with the canvas.
Yes it's a kludge but it just may work.
To make a DiagramBuilder read-only, you can detach() events from all of its children recursively:
/*
* Readonly the diagram
*/
function ReadonlyDiagram(diagram) {
function detachRecursively(node) {
node.get('children').each(detachRecursively);
// You may also want to set the cursor to the default since it will
// change based on which elements the mouse is over.
// node.setStyle('cursor', 'auto');
// You may want to detach specific events such as 'click' or
// 'mousedown' if you do not want to disable all events.
node.detach();
};
diagram.on('render', function (event) {
detachRecursively(diagram.get('boundingBox'));
});
}
Now, you must be post diagramBuilder object to ReadonlyDiagram function like below codes:
YUI().use('aui-diagram-builder', function (y) {
var diagram = new y.DiagramBuilder(
{
availableFields: data,
boundingBox: '#' + containerId,
fields: nodes,
srcNode: '#' + builderId
}).render();
diagram.connectAll(connections);
if (callBackDiagram !== undefined) callBackDiagram(diagram);
if(isReadonly === true) ReadonlyDiagram(diagram);
});
});
Reference
The title explains it all...
I need to perform a custom action when I know a user has finished resizing, but from what I can find in the Kendo UI documentation there is no event for this accessible to me other that 'resize' which I cannot use as is.
Perhaps i just missed the event?
if not:
Is there a way to use the 'resize' event to determine that a user has stopped resizing?
So here's my answer thus far:
Mine differs slightly due to architectural needs, but here's a general solution
var isResizing = false;
var wndw = $(element).kendoWindow({
// .....
resize: OnResize,
// .....
}).data('kendoWindow');
function onResize() {
isResizing = true;
}
$('body').on('mouseup', '.k-window', function() {
if(isResizing){
// **Your 'Stopped' code here**
isResizing = false;
}
});
Have you considered using underscore.js debounce? I have used it successfully to only trigger then change after the resize events have stopped coming for a certain period (in the case below 300ms). This does add a small delay to captureing the end, but if like me you just want to store the final size then that works fine. Here is the version of the code above but using underscore debounce:
var wndw = $(element).kendoWindow({
// .....
resize: _.debounce( this.hasResized, 300)
// .....
}).data('kendoWindow');
//This is called at the end of a resize operation (using _.debounce)
function hasResized (args) {
// ** Your code here **
};
Hope that helps.
Here's the scenario
$("p").live('customEvent', function (event, chkSomething){
//this particular custom event works with live
if(chkSomething){
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
}
})
Here's some background
The custom event is from a plugin called inview
The actual issue is here http://syndex.me
In a nutshell, new tumblr posts are being infnitely scrolled via
javascript hack (the only one out there for tumblr fyi.)
The inview plugin listens for new posts to come into the viewport, if the top of an image is shown, it makes it visible.
It's kinda working, but if you check your console at http://.syndex.me check how often the event is being fired
Maybe i'm also being to fussy and this is ok? Please let me know your professional opinion. but ideally i'd like it to stop doing something i dont need anymore.
Some things I've tried that did not work:
stopPropagation
.die();
Some solutions via S.O. didnt work either eg In jQuery, is there any way to only bind a click once? or Using .one() with .live() jQuery
I'm pretty surprised as to why such an option isnt out there yet. Surely the .one() event is also needed for future elements too? #justsayin
Thanks.
Add a class to the element when the event happens, and only have the event happen on elements that don't have that class.
$("p:not(.nolive)").live(event,function(){
$(this).addClass("nolive");
dostuff();
});
Edit: Example from comments:
$("p").live(event,function(){
var $this = $(this);
if ($this.data("live")) {
return;
}
$this.data("live",true);
doStuff();
});
This one works (see fiddle):
jQuery(function($) {
$("p").live('customEvent', function(event, chkSomething) {
//this particular custom event works with live
if (chkSomething) {
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
$(this).bind('customEvent', false);
}
});
function doStuff() {
window.alert('ran dostuff');
};
$('#content').append('<p>Here is a test</p>');
$('p').trigger('customEvent', {one: true});
$('p').trigger('customEvent', {one: true});
$('p').trigger('customEvent', {one: true});
});
This should also work for your needs, although it's not as pretty :)
$("p").live('customEvent', function (event, chkSomething){
//this particular custom event works with live
if(chkSomething && $(this).data('customEventRanAlready') != 1){
doStuff();
// BUT only per element
// So almost like a .one(), but on an elemental basis, and .live()?
$(this).data('customEventRanAlready', 1);
}
})
Like Kevin mentioned, you can accomplish this by manipulating the CSS selectors, but you actually don't have to use :not(). Here's an alternative method:
// Use an attribute selector like so. This will only select elements
// that have 'theImage' as their ONLY class. Adding another class to them
// will effectively disable the repeating calls from live()
$('div[class=theImage]').live('inview',function(event, visible, visiblePartX, visiblePartY) {
if (visiblePartY=="top") {
$(this).animate({ opacity: 1 });
$(this).addClass('nolive');
console.log("look just how many times this is firing")
}
});
I used the actual code from your site. Hope that was okay.
I apologize if this has been asked before but, is there a way to add an event listener/handler to a Javascript object? Preferably using JQuery.
Such as:
var foo;
$(foo).bind('change', function() {
alert("Foo has changed!");
});
I have tried this, but nothing seems to happen. Does this only work with DOM elements?
EDIT:
I need an event fired every time that the audio or video tags throw an error. Originally, I was using an interval to check whether or not the error, 'media.error', object was null, but this uses excess processing power and I would like to avoid it.
EDIT 2: Apparently I was going about it wrong, easiest way I found was to add the "onerror" property to the video/audio tag.
I agree with Cheeso that it's more important for you to state what you actually want to do, however one workaround for your specific question could be to store your variable within an object and only provide access through getter / setter, then you can do what you want in the setter. e.g.
function data() {
var foo = 0;
this.setFoo = function(newVal) {
foo = newVal;
alert(foo);
};
}
var theData = new data();
theData.setFoo(5);
Yes, that's correct. You cannot make a "variable watcher". There is no event fired for variables when they are changed.
What are you really trying to do?
You could try:
http://higginsforpresident.net/js/static/jq.pubsub.js
See
http://weblog.bocoup.com/publishsubscribe-with-jquery-custom-events
Or use a framework like backbone/underscore or knockout.js.
HTML/Elements/audio
var foo;
$(foo).bind('error', function() {
//your code here
});
How do you keep track of your UI elements in Titanium? Say you have a window with a TableView that has some Switches (on/off) in it and you'd like to reference the changed switch onchange with a generic event listener. There's the property event.source, but you still don't really know what field of a form was just toggled, you just have a reference to the element. Is there a way to give the element an ID, as you would with a radiobutton in JavaScript?
Up to now, registered each form UI element in a dictionary, and saved all the values at once, looping through the dictionary and getting each object value. But now I'd like to do this onchange, and I can't find any other way to do it than create a specific callback function for each element (which I'd really rather not).
just assign and id to the element... all of these other solution CAN work, but they seem to be over kill for what you are asking for.
// create switch with id
var switcher0 = Ti.Ui.createSwitch({id:"switch1"});
then inside your event listener
myform.addEventListener('click', function(e){
var obj = e.source;
if ( obj.id == "switch1" ) {
// do some magic!!
}
});
A simple solution is to use a framework that helps you keep track of all your elements, which speeds up development quite a bit, as the project and app grows. I've built a framework of my own called Adamantium.js, which lets you use a syntax like jQuery to deal with your elements, based on ID and type selectors. In a coming release, it will also support for something like classes, that can be arbitrarily added or removed from an element, tracking of master/slave relationships and basic filter methods, to help you narrow your query. Most methods are chainable, so building apps with rich interaction is quick and simple.
A quick demo:
// Type selector, selects all switches
$(':Switch')
// Bind a callback to the change event on all switches
// This callback is also inherited by all new switch elements
$(':Switch').bind('change', function (e) {
alert(e.type + ' fired on ' + e.source.id + ', value = ' + e.value);
});
// Select by ID and trigger an event
$('#MyCustomSwitch').trigger('change', {
foo: 'bar'
});
Then there's a lot of other cool methods in the framework, that are all designed to speed up development and modeled after the familiar ways of jQuery, more about that in the original blog post.
I completely understand not wanting to write a listener to each one because that is very time consuming. I had the same problem that you did and solved it like so.
var switches = [];
function createSwitch(i) {
switches[i] = Ti.UI.createSwitch();
switches[i].addEventListener('change', function(e) {
Ti.API.info('switch '+i+' = '+e.value);
});
return switches[i];
}
for(i=0;i<rows.length;i++) {
row = Ti.UI.createTableViewRow();
row.add(createSwitch(i));
}
However keep in mind that this solution may not fit your needs as it did mine. For me it was good because each time I created a switch it added a listener to it dynamically then I could simply get the e.source.parent of the switch to interact with whatever I needed.
module Id just for the hold it's ID. When we have use id the call any another space just use . and use easily.
Try This
var but1 = Ti.Ui.createButton({title : 'Button', id:"1"});
window.addEventListener('click', function(e){
var obj = e.source;
if ( obj.id == "1" ) {
// do some magic!!
}
});
window.add(but1);
I, think this is supported for you.
how do you create your tableview and your switcher? usually i would define a eventListener function while creating the switcher.
// first switch
var switcher0 = Ti.Ui.createSwitch();
switch0.addEventListener('change',function(e){});
myTableViewRow.add(switch0);
myTableView.add(myTableViewRow);
// second switch
var switch1 = ..
so no generic event listener is needed.