How do I check if a fabric Object is a video? - fabricjs

Fabricjs seems to use fabric.Image to create both an image or a video. In multiple use cases if I'm getting some fabric object, through an event, or looping through the fabric canvas, I need to differentiate if that object is an image or a video. If I use fabricObject.type I will get "image" type for both the video object and the image object. Is there some other property I can check to determine which is which? Perhaps there is a way to add metaData to the fabric.Object to help differentiate objects.

Ok, so I found out that I can use the data field inside a fabric object to store any type of data I want, without fabric messing with it. This will help immensely and I've tested that it works.

Related

How to uniquely identify animations?

I'm trying to access Animation's but so far the only method I could think of was:
tool
...
set_meta("animation_path",["NodePath/to/AnimationPlayer","Animation Name"])
var ani_data=get_meta("animation_path")
var animation=get_node(ani_data[0]).get_animation(ani_data[1])
but the problem is that if I change the Animation Name I'll have to reset the value, so is there no way to store a unique id for Animation resource?
I tried storing get_instance_id() & using instance_from_id() but that doesn't work when I restart the game engine
If the Animation is saved
Given that Animation is a Resource, I believe you can use the resource_path (given the Animation is saved).
The resource_path represents where the Resource is saved, and thus it persists when you restart the game engine.
Also, it would be unique for each Resource (it is possible to have multiple Resources saved in the same file, but then the resource_path of each Resource points to a sub-resource of the file).
And yes, the resource_path does not change when you rename the Animation.
The other idea that comes to mind is that the Animation itself has metadata which you could use.
If you will not be using the animation name, you would have to iterate over the Animations of the AnimationPlayer to find the one you want.
I suppose that if you use the resource_path, you could load it and get the animation name form there. You could also be getting the same instance… That happens if you are getting it from cache.
If the Animation is not saved.
First of all, storing metadata on the Animation should still work. Except, of course, it still means to iterate over the Animations to find the correct one.
If the goal is to not do that, then you can hold a Dictionary with String for keys and Animations as values, and keep it somewhere you know there is only one instance. For example:
Store it in an EditorPlugin.
Store it in an Autoload.
Store it in a specific Resource which you preload.
Store it on a const. Godot will admit Dictionary and Array as consts. Making them consts means you cannot set them… But they are still mutable. Furthermore, consts are shared among instances.

We want to change the colour of the model with passing the DBId without selection. #AutodeskForge

In 3d Model of Autodesk Forge, We want to change the colour of the model with passing the DBId without selection. How can we do it? please help on this.. we are unable to find any reference on this.
If you already have a dbID of an object you'd like to color, you can use the viewer's setThemingColor method.
If you're asking about how to get dbIDs of objects without selecting them, there are different ways. For example, you can iterate through the scene hierarchy (as explained in this blog post), or obtain dbIDs of objects with specific properties (using the getProperties method).

global identifiers? - iCloud + Core Data + Ensembles - duplicates when deleting objects

I am trying to implement iCloud sync in my Core Data app. I am not that pro in programming and this is really an advanced topic I learned... I found that Core Data sync Framework "Ensembles" by Drew McCormack. It seems to make iCloud Sync much easier.
I integrated it in my App and syncing does work quite well as long as I add new objects to my Core Data model. But when I delete an object, it creates duplicates. And then duplicates from duplicates. I ended up having the same Entry (object) like 3-4 times...
Why is that? What am I doing wrong? I did some research and my guess is that global identifiers could solve this?
What are global identifiers? My guess is that they help to avoid duplicates!? But how do I set this? I really have no idea, did a lot of research but couldn´t find an answer to that.
Thanks for help!
Update:
Thanks for help! I read the readme and the book, but since i am beginner not everything is clear to me.
I think I understand the use of global identifiers in Ensembles now, but I don´t know if I´m doing it correctly.
If I understand it right, I have to assign an identifier to each object. I can do this by storing it in an attribute. This identifier can be anything as long as it is unique and a NSString?
In my app the user can store different things, let´s say name, text, title, date and so on. The app is based on the Master-Detail-View template in Xcode and uses Core Data. My Core Data model has only a single entity with some attributes, most are strings and a NSDate. No relationships or anything. If the user hits "+" a new object is created and I store the things the user enters in the attributes.
What I did to add global identifiers is to add a new attribute that stores it.
So when a new object is created i do
/// I did find that to use as identifier !?
NSString *taskUniqueStringKey = newManagedObject.objectID.URIRepresentation.absoluteString;
/// and store it in the attribute.
[newManagedObject setValue:taskUniqueStringKey forKey:#"coreDataObjectID"];
Then i use this:
- (NSArray *)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble globalIdentifiersForManagedObjects:(NSArray *)objects
{
return [objects valueForKeyPath:#"coreDataObjectID"];;
}
This seems to work for me. But am I doing it right? Is this the right place to assign a global identifier? I have no awakeFromInsert !?
If this is working, I got the next problem. My app is already live and older entries that the user saved before the update will be missing the global identifier. What can I do about that? I thought what I already got and what is unique and the only thing I can think of is an attribute that saves [NSDate date] when the object is created.
I was trying to use this but I failed because Ensembles will only accept NSString and not NSDate!? Can I use this date attribute, is this unique enough and working as gloabl identifier? And if yes, could you please give me code example in how to convert this from date to string?
Syncing with Ensembles works quite good. No duplicates anymore, you can just switch off iCloud and the entries stay and switch it on again and it syncs like it should without loosing locally stored objects or so. Ensembles is really cool! I am seeing some minor strange behaviors like sometimes sync takes long, sometimes it´s really quick and if I edit things in a short time period on two different devices it gets a bit messed up like an object that I just deleted reappears. But I guess that´s normal? If I take some time between using the app on the different devices everything works fine.
Do I understand it right, there is only that one method to call for sync:
- (void)syncWithCompletion:(void(^)(void))completion
{
if (self.ensemble.isMerging) return;
if (!self.ensemble.isLeeched) {
[self.ensemble leechPersistentStoreWithCompletion:^(NSError *error) {
if (error) NSLog(#"Error in leech: %#", error);
if (completion) completion();
}];
}
else {
[self.ensemble mergeWithCompletion:^(NSError *error) {
if (completion) completion();
}];
}
and you just call it if needed? There is nothing else like doing merge without leeching before, or a method like "this is the actual status - save it like it is now" ?
There are different points in the app where you want to sync. On app start and when terminating will be a good point. In my app there are two points where I should sync I guess: when adding an object and save it to Core Data and when I save changes to the object. I could also provide a button like "sync now". Is this a good approach and do I always just call
[self syncWithCompletion:NULL];
Another question that came up. Can I exclude objects from sync with Ensembles? My app loads tutorial entries as objects once on first app start. I don´t want to sync them if that´s possible somehow?
Thanks a lot for your help! If I could help you with anything like localizing in german or so let me know ! ;)
Yes, this is almost certainly due to not setting up global identifiers for your objects, or at least not doing it properly.
When you leech your ensemble, the local persistent store is imported into the sync data. Without global identifiers, Ensembles will assign random ids to your objects, so it can track them across devices.
Duplicates arise when you leech a second device that has the same data. Ensembles has no way to know that the data represents the same logical objects as on the other device, so it again assigns random ids. Effectively, it treats the objects on each device as being completely independent, so that all end up in your data set after syncing.
The solution is global identifiers. By implementing a CDEPersistentStoreEnsemble delegate method, you can provide Ensembles with global ids, which it can use to identify which objects on different devices belong together.
What should you use for global ids? Often, just a UUID, though for singleton like objects you will just want to pick an id.
You can initialize them in awakeFromInsert. You can store the global ids in attributes on your entities. (Note that if you are migrating an existing app, you will want to check with a fetch if the global ids have been generated BEFORE you try to leech the store for syncing.)
More details are in the README on GitHub and in the book at leanpub.
Update
To answer your update questions:
Yes, an identifier just has to be a string, and immutable. It should not change once assigned.
The NSManagedObjectID is not a very good global identifier, in that it will be different on different devices. We really want something that is global across devices.
If you are starting from scratch, using NSUUID is a good approach. Just create a unique id, and store it in the object.
If you have an existing app, and it has been syncing via another mechanism, you need to come up with a way to provide the same global identifiers on each device. One way to do that is mash up the object properties in some way. Usually that will give you a pretty-close-to-unique value, and it will be good enough for the transition.
As an example, you do a quick fetch, and discover that your objects don't yet have global ids. You go through the objects, and set the global ids to a string comprised of creationDate + text. (You could even shorten this by taking a hash, but it probably isn't that important.) After this initial 'migration' to global identifiers, you would just use UUIDs for any newly created objects.
Note that you don't have to use awakeFromInsert. That is simply a convenient place to put it. As long as you assign the global identifier before saving the object you should be fine.
The easiest way to get a string from an NSDate is to call the description method, but another way would be to get a double using timeIntervalSince1970, and turning that into a string. (Be careful with dates as unique identifiers on their own: often objects created together will have the same creation date.)
You are correct about how you should do a sync: you can simply call syncWithCompletion:.
To answer the question about excluding objects: You can't exclude individual objects, mainly because it could become tricky when those objects have relationships to synced objects. You can handle these objects in one of two ways:
Put them in a separate persistent store, and add that store to the same persistent store coordinator.
Sync the objects, but give them global ids manually, so that the objects are treated the same on each device. Eg. You could just give global ids as 'Sample1', 'Sample2', etc.
To integrate Drew's answer, I guess the two steps are the following.
1 Implement CDEPersistentStoreEnsemble delegate method (see README)
- (NSArray *)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble
globalIdentifiersForManagedObjects:(NSArray *)objects {
return [objects valueForKeyPath:#"yourUniqueIdentifier"];
}
2 Generate the unique identifier for a NSManagedObject subclass
- (void)awakeFromInsert {
[super awakeFromInsert];
if (!self.yourUniqueIdentifier) {
self.yourUniqueIdentifier = [[NSUUID UUID] UUIDString];
}
}
In awakeFromInsert you can initialize special default property values, like for example an identifier.
The check is necessary, for example, when you have parent-child contexts. Otherwise you are overwriting the identifier previously set. See Why is awakeFromInsert called twice?.

Cocoa Bindings not updating NSTextField value

I have two windows, one is a table view to display content. One is a window for inputting content.
I have an NSTextField binded to a property in my app delegate. When I change a value in the text field, the app delegate property will change. However, if I go the other way and programmatically change the property's binded key, the value of the text field does not update. However, it does in the table view.
What is going wrong here? How can I update text field?
EDIT:
I tried all 3 of these with the same result
[_addEntry setValue:#"Chet" forKey:#"payee"];
[_addEntry setPayee:#"chet"];
_addEntry.payee = #"chet";
EDIT:
Here's a simple example to elaborate on my point
https://dl.dropboxusercontent.com/u/48014761/test.zip
the label and the textfield are bound to the "str" property. It is initially null. press log to see that in the console. press change str button to change the string. Log to verify. Note that the label and the textfield do not update!
EDIT:
"What am I trying to accomplish?"
Here's the project I am working with:
https://dl.dropboxusercontent.com/u/48014761/Write-Offs.zip
I am trying to use Cocoa Bindings as much as possible. I have a table with a bunch of data. However, each entry is going to have an array of images associated with it. Thus, when I add a new entry, I need to open up a new window so I can set the properties of that entry (rather than through the table) along with upload some images.
I am not sure I am implementing the addEntryWindow correctly. It seems like I should create and destroy the window each time I open and close it. This doesn't appear to be happening.
Also, [[self addEntry] setDate:[NSDate date]]; doesn't seem to fix the problem for me.
Thanks
Chet
How are you programmatically changing the field? Are you using KVO? Is the field inside of a NSManagedObject instance?
Bindings work through KVO. Core Data disables some aspects of KVO for its own internal uses and you might be tripping over one of those.
Update your question with the code sample and lets see what is going on.
Update
Both windows don't necessarily need to be in the same xib but they do need to be talking to the same instances. Ideally they should both be talking to the same instance of NSManagedObject and therefore talking to the same NSManagedObjectContext.
Who is the owner of each window?
Is the owner the same?
If not, is a new Core Data stack being created?
Update
In your test, I was able to correct it by how you were editing the property
- (IBAction)press:(id)sender {
[self setStr:#"this"];
}
You were accessing the iVar directly instead of the property. When you access the iVar directly KVO does not fire.
In addition, in your xib files you were accessing self.str which is unnecessary. It should be just str.
Are you doing any direct property access in your actual project?
Update
You can do a get accessor and then a set accessor:
[[self addEntry] setPayee:xxx];
Based on the variables you are using I wonder what you are trying to accomplish. Can you post the exact code of the programmatic change you are trying to enact?

Attaching arbitrary data to objects in D3.js

This relates mostly with what a "best practice" would be with D3.js. I want to attach arbitrary information to different svg elements that I have on a page, after they are created. In D3, it looks like one generally generates svg elements from a dataset. I want to attach data to these svg elements at any time, without adding their HTML attributes.
Is there a good way of doing this? Do I need to use an auxillary array/object or is there a way to apply data to the elements themselves?
You would use the datum method if you want to attach arbitrary data:
D3.select('#mynodeId').datum( mydata );
And then later you could access the value again:
var mydata = D3.select('#mynodeId').datum();
Internally, D3 is going to use the __data__ property of the node, just like it does when the nodes were created from a data set via the selectAll, enter, append sequence.
Note that if you already have a reference to a DOM node you can pass it as the parameter to D3.select rather than making it re-look-up based on selector syntax:
D3.select( anExistingDOMNodeReference ).datum( mydata );
From the API doc:
d3.select(node): Selects the specified node. This is useful if you already have a reference to a node, such as d3.select(this) within an event listener, or a global such as document.body.

Resources