How to properly use HTML5's canvas within JavaScript classes? - javascript

First off, I use the term "classes" to mean functions with prototypes that might be in a separate file from the main initializing file for what I'm working on.
Now for my question/issue:
I'm working on building something in JavaScript/HTML5, and trying to program it "properly" (ie. using prototypes with formats that are, I hope, standard). In my main JavaScript file, I have methods that have create use an instance (basically the root instance of my OOP/prototype based script) that sets up the canvas.
I also have another file that is loaded which contains a 'class' for creating clickable buttons. As of right now, I'm just trying to get the buttons to draw on the canvas, however, I can't access the instance of the canvas because I believe the instance is out of scope (which is fine, I don't want everything I do to contain a long dot-notation for referencing instances). However, this is giving me trouble when trying to draw a rectangle on the canvas, considering the 'class' the button is in, isn't able to reference the context outside of it.
I found a way around this by using something along the lines of:
function CreateButton(btn_x, btn_y, btn_width, btn_height, btn_txt) {
// ... (check and define parameters)
CreateButton.prototype.custom_canvas = document.getElementById('root_canvas');
CreateButton.prototype.ctxt = this.custom_canvas.getContext('2d');
CreateButton.prototype.ctxt.fillStyle = '#666666';
CreateButton.prototype.ctxt.fillRect(this.x, this.y, this.width, this.height);
}
Basically, it's writing on top of the canvas with a canvas of the same name? I'd assume that I can still manipulate the regular canvas afterwards and it would just act as if it was a single canvas element. I worried that redrawing on the canvas might use up a lot of memory when many things are added, however, no matter the method, writing on top of the canvas can't be avoided (even when in the same scope).
Any suggestions, or help? Or is my method of using the same canvas within a different class acceptable?
Thanks for any feedback.
[UPDATE]
Hmm, maybe I should try passing the context as a parameter and just using that.
...Or should I just make the canvas a global object? Any suggestions?

I guess you could try to implement some sort of "WidgetManager" that retains reference to canvas and your widgets. It will use a callback mechanism to render widgets. Each widget (ie. in this case Button) will have certain kind of rendering states (pressed, released) and some kind of internal state. Other widgets might have more complicated states.
Note that "WidgetManager" should probably keep track of widget "z" and user presses (which widget was hit). Based on this it should be able to trigger handlers bound to widgets. In a way you have to reinvent what basic UI libs do already. :)
I think you are better off by working out your design this way before moving into the implementation phase. A lot depends on what you really want to with it. :)
Note that you can simplify rendering and checks a lot by using multiple canvasii instead of just one. In this case you'll have to deal with z-index and absolute positioning but at least you get to piggyback on some of the existing stuff without having to implement it yourself.

Related

Overriding Canvas / DOM object properties dynamically

I am trying to override a few properties in at the Object level for native JavaScript objects but I am struggling to figure out how to do this globally / correctly. This is done for privacy purposes to avoid fingerprinting.
For example I would like to override the UNMASKED_VENDOR_WEBGL, UNMASKED_RENDERER_WEBGL, and getSupportedExtensions() values from a query as below.
let e = document.createElement("canvas").getContext('webgl');
var t = e.getExtension("WEBGL_debug_renderer_info");
e.getParameter(t.UNMASKED_VENDOR_WEBGL);
e.getParameter(t.UNMASKED_RENDERER_WEBGL);
e.getSupportedExtensions();
For most properties for example at the navigator or screen levels I can just use Object.defineProperty or even directly rewrite the functions to just return what I want. However for the example above it's a bit more tricky because it needs to apply for any canvas created. I cannot access the specific canvas DOM element because I don't think there is a on createElement trigger as far as I know and the crafty creator of this extremely invasive fingerprinting code does this dynamically from WASM...
I have the same issue overriding the canPlayType on (new Audio) instance.
If anyone knows a trigger event I can use for on creteElement or better yet how I can spoof this it would be a huge help!

Animate CC - getChildByName canvas vs WebGL

Afternoon. I have an FLA with a single MovieClip on the stage - the clip is named myThing in the Library and also has an instance name of myThing. On another layer I have the following script:
this.myThing=this.getChildByName("myThing");
console.log(this.myThing);
When I run this in a WebGL project it works as I'd expect and returns a JS object but when I run the same thing in a canvas project (which is what I need to use) it comes back null.
Initially, can anyone explain what the difference is between a WebGL and a canvas project in Adobe Animate CC and how I can get a reference to child clips to control their timelines?
Along with that, can anyone point me to any decent resources on scripting these projects? It seems like no matter what I search for I always end up back at that *!#%£¡ rabbit tutorial that manages to cram very little info into an awful lot of words.
Thanks all, your help is always appreciated :)
So I was being a numpty.
The name property of any asset defaults to null. This is not a problem because the getChildByName() method is not really necessary (for me at least) once I realise that you can just call this.someChild.someMethod().
I got hooked up on the wrong approach because it was the only one I could find examples of. I'm still finding documentation very sketchy and not very helpful when compared to AS3 or even competing JS libraries like Greensock
Also not sure why my first approach worked in WebGL but not canvas. Ah well, onwards and upwards...
WebGL and HTML5 Canvas documents work somewhat differently in Animate CC.
In WebGL, symbols having instance names are accessible as follows:
var mySymbol = this.getChildByName("instance-name");
In Canvas, the same can be done as follows:
var mySymbol = this.instance-name;
Unnamed instances can be referenced using this.getChildAt(index) in both canvas and WebGL.
Once a reference to the required instance is obtained, you can easily control it as desired. (gotoAndPlay()/Stop() etc.)
PS: In canvas, Symbol-instance names are not explicitly set as name properties of corresponding symbols in the output - hence the name property is returned as null.

What is the difference between Container and DisplayObjectContainer?

I am using a JavaScript library called PIXI and am looking for a way to "zoom" in my game. A search on the internet suggested that I put everything inside a DisplayObjectContainerand then resize it to simulate a zoom-effect.
The thing is that I already have Container (aka stage), and I think that is resizable too. So I don't understand the reason behind using a DisplayObjectContainerwhen you have a Containeralready. And frankly, I don't even see the difference between them.
This page says the following about DisplayObjectContainer:
A DisplayObjectContainer represents a collection of display objects. It is the base class of all display objects that act as a container for other objects.
This other page says the following about Container:
A Container represents a collection of display objects. It is the base class of all display objects that act as a container for other objects.
The only possible scenario I can imagine is that one of these container-objects is outdated and belongs to an older version of PIXI, which isn't too unrealistic since PIXI is rather new and could change a lot. But this is just a guess.
The guess is correct. DisplayObjectContainer is outdated and replaced with Container.

dojox gfx make a node moveable after getting sgv from json

I have a surface with some shapes. I use
dojox.gfx.utils.toJson(surface)
to generate a json from it, and then
dojox.gfx.utils.fromJson(surface, json)
to get the data and append it to the surface.
The problem comes when I create a moveable node. After saving it to json and then appending it to the surface, the node is no longer moveable. I found no way of making the node moveable again. Is there a way to do this?
I want to be able to save and load svg data in my page and after load, move the elements around. Using dojo seemed easy enough before i stumbled on this problem. If I can't do this easy, is there a better library I can use, to achieve my goal?
Edit: here is the actual code: http://pastebin.com/2qLCTw8B
I found the answer to my problem.
First of all, when you require a dojo module it is good to assign it to a variable, which i didn't know. This way when assigning the on module, you can use the on function, used to add event listener, anywhere in the code. From there it is easy to create a moveable node, when you click on it.
It seemed though that this is a useless operation, as you could just iterate over the surface - children array, and make every node moveable.
Here is the improved code: http://pastebin.com/wAvSnZpN
The code needed, if you decide to use events anyway:
function HandleMouseDown(e) {
var foo = new dojox.gfx.Moveable(e.gfxTarget);
}
on(surface, 'mousedown', HandleMouseDown);

Javascript: call a function defined in a variable without eval

I'm writing a jQuery plugin that hooks to scroll and drag events, and rotates an element to point towards another element when a relevant event is triggered. Basically my plugin just detects the events, calculates the correct angle, and rotates the element accordingly using a third-party plugin. For a better explanation, you can see the demos of my plugin.
I don't want to force a certain rotation plugin to be used, so the rotation function's name may vary. At the moment I'm using eval to allow for custom function names, but I'd like to find another way of doing this. I've tried googling, but so far haven't found a solution.
So, is there a way to get around this? The rotation function's name is stored in settings.rotateFunction:
eval("$(this)." + settings.rotateFunction + "(angle)");
So far I've tried the "new Function(codeToEval)" method, but this for some reason breaks the use of $(this).
In Javascript object members (properties or functions) can be accessed using these two notations:
object.memberName
object["memberName"]
The second one is especially useful when member isn't known during design-time but rather during runtime. That's why you can call your rotate function this way:
$(this)[settings.rotateFunction](angle);
Use following syntax:
$(this)[settings.rotateFunction](angle);

Categories

Resources