2

After several hours of trying to figure this out and reading documentation, I'll surrender on this one. I come from a C/C++ background trying to learn Javascript and I'm getting a little confused on what the difference is between a DOM element and an Object. I thought I understood but when I call certain functions on Objects, like ".addEventListener()" I get the famous "Undefined is not a function" error, amongst other funny things. So here's two attempts at the same thing using SVG.js. I'm basically just trying to add an event listener to every shape that I've generated inside of my SVG canvas thus far, such that when any shape is clicked it will change color independent of all others.

One gives me "Undefined..." on the add event listener line, which I solved with the second version but now I'm getting the "Undefined..." error on the only declaration inside of my function.

Could you clarify what the difference is between a DOM element and an Object and then help me understand why the "Undefined is not a function" error is popping up in my second example? Thanks.

Version 1: canvas.get() returns an object, one of the shapes I've generated, error appears on .addEventListener() call

function changeColor(e) {
    this.fill({color: currentColor});
}
//add event listeners for every element of SVG
var it;
for (it=3; it<=18; it++){
    var canvasName = canvas.get(it);
    canvasName.addEventListener("click", changeColor);
}

Version 2: the event listener is now being added to a DOM element and the "Undefined is not a function" error appears in declaration inside of function (line 2)

function changeColor(e) {
    this.fill({color: currentColor});
}
//add event listeners for every element of SVG
var it;
for (it=3; it<=18; it++){
    //get string to search for id in DOM
    var idName = "SvgjsRect" + (1006+it);
    var box = document.getElementById(idName);
    box.addEventListener("click", changeColor);
}

My final version. I realized that they basically abandon all native DOM functions for their own, so I used their event binding methods.

var changeColor = function() {
        this.fill({color: currentColor});
    }
    //add event listeners for every element of SVG
    var it;
    for (it=3; it<=18; it++){
        var box = canvas.get(it);
        box.on('click', changeColor);
    }
Aaron Chamberlain
  • 653
  • 2
  • 10
  • 26
  • The "this" keyword within changeColor does not refer to what you think it does... what object has the fill method defined? – Brian Mains Jun 30 '15 at 01:21
  • in svg.js the .fill( ) function is defined for all the shape prototypes (Rect, Circle, etc....). Looking at it, I don't think I'm passing it a shape object in version 2, but rather the DOM reference, so that could be it, but then again it won't let me add an event Handler to object itself, so don't know the workaround for that.... Printed out the object using console.log and see that for onclick is null. Shouldn't it be paired with a function? And if it's not paired, how did it enter into changeColor( )? – Aaron Chamberlain Jun 30 '15 at 01:29

1 Answers1

0

Having skimmed through the docs for svg.js it appears that it doesn't expose the underlying DOM Element at all. There are no methods that return the underlying DOM object nor are there any properties that point to it.

The svg.js shapes objects are wrappers around then underlying DOM objects. The DOM and the DOM Elements are ultimately implemented in C/C++ and exposed to javascript as objects. They're not ordinary objects however because they're not implemented in javascript. For example, in most implementations DOM objects don't have constructors.

Basically, in C++ terms, the relationship between svg.js shapes and DOM elements is this:

class DOMElement {
    /* DOM methods like .addEventListener() */
}

class shape { // from svg.js
    private DOMElement element; // you have no access to this

    /* svg.js shape methods such as .fill() */
}

One work-around that you've discovered is to use DOM APIs to get the DOM object (document.getElementById). But then you're trying to call an svg.js method on the DOM object which of course fails.

So the fix to the version 2 of your code is to use DOM APIs to set the fill:

function changeColor(e) {
    .setAttribute('fill',currentColor);
}

Fortunately, the svg.js library also provides event binding methods so you don't need to use DOM APIs to add an event listener. So an alternative solution would be to replace .addEventListener() instead:

for (it=3; it<=18; it++){
    var canvasName = canvas.get(it);
    canvasName.click(changeColor);
}

However, do note that svg.js event listeners are non-standard in that it doesn't pass the event object as an argument. So you shouldn't have that (e) argument if you were to do this. If you need to use (e) then you need to use the DOM API above.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • I strongly recommend reading the svg.js docs: http://documentup.com/wout/svg.js . In order to answer this question I merely skimmed through it so just doing a find will probably answer most questions you may have. – slebetman Jun 30 '15 at 05:42
  • Thanks for that explanation, made sense, I had been reading the docs for the library but missed the event handling I guess. I'll answer with my now working solution to help anyone else but how do I also give you credit for your contribution? – Aaron Chamberlain Jun 30 '15 at 06:23
  • in 2k18 you can just use `element.on('eventName', fn)` just in case somone stumbles about this now – Fuzzyma Feb 15 '18 at 11:04
  • No Ofc the on method is defined on the svg.js objects and not on the Dom elements. Use the wrapper elements of svg.js. Anyone else makes no sense when you are using the svg.ja library – Fuzzyma Feb 19 '18 at 11:40