0

This question refers to kineticJS but the problem is about the basic logic of nested functions I believe. I have a kineticjs stage on a div:

<div id="container"></div>

The kineticjs script puts a shape on the stage:

function displayVizualization(){
    //SKETCH SIZE
    var SKETCH_WIDTH = 800;
    var SKETCH_HEIGTH = 800;


    var stage = new Kinetic.Stage({
        container: document.getElementById('container'),
        width: SKETCH_WIDTH,
        height: SKETCH_HEIGTH
    });
    var layer = new Kinetic.Layer();

    var rect = new Kinetic.Rect({
        x: 239,
        y: 75,
        width: 100,
        height: 50,
        fill: 'green',
        stroke: 'black',
        strokeWidth: 4
    });

    // add the shape to the layer
    layer.add(rect);

    // add the layer to the stage
    stage.add(layer);

    function updateViz(){
        console.log("we are in the updateViz function")
        var count = document.getElementById("formID:counter").value;
        console.log("count is: "+count);
        rect.transitionTo({
            x: 100*count,
            duration: 2,
            easing: easing
        });
    }
}

I need to call the function "updateViz" from another script on this page in an oncomplete attribute. I have something that says:

oncomplete: updateViz();

But of course I get an "function not defined" error because updateViz() is nested in displayVizualization().

How should I call updateViz() then? Thx!

[EDIT: moving updateViz() outside displayVisualization() is perfectly fine with me. But then please explain how the variables in updateViz should refer to the variables in displayVisualization?]

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
seinecle
  • 10,118
  • 14
  • 61
  • 120

2 Answers2

1

Basically, you can't, unless you modify displayVisualization to return a reference to the updateViz within it (or more significant refactoring). This is because there isn't one updateViz function, there's one for each call to displayVisualization. They refer to ("close over") different references to rect*, where the rect in question depends on the call.

Let's use a simpler example:

function foo(n) {
    setTimeout(bar, 1000);

    function bar() {
        console.log(n);
    }
}
foo(10);
foo(20);

What happens with the code above? You clearly know your stuff, so the answer is that the first call to foo sets up a delayed function call that will happen a second later and log "10" to the console. The second call sets up logging "20".

But why? Because there is no one bar function: A bar function is created each time we call foo, and refers to the execution context in which it was created (the context created by the call to foo).

If you modified displayVisualization to return a reference to updateViz, then you could use that return value to call updateViz, because it would refer to each function as appropriate.


(I should mention that most modern JavaScript engines won't actually duplicate the code for bar, they'll just create multiple function objects that refer to the same underlying code with a different execution context pointer. But that's an implementation detail.)


* Technically, they don't close over different rect references, they close over something called an execution context which contains rect amongst other things. More about closures: Closures are not complicated

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

In case the above snippet is loaded as a separate js file, you can assign a variable to the container function and return a reference to your function

var displayVizualization = function (){
...
return { updateViz:updateViz }
}

Now you can call this function updateViz using

displayVizualization.updateViz()
Ani
  • 1,655
  • 3
  • 23
  • 37