I am working on a web mapping library, that makes it possible to create a map with SVG and JavaScript. As every map shall consist of SVG and Image elements, which can be grouped in layers, which in turn can be set invisible, I need an API to reflect this functionality. I started with two classes/prototypes:

Map()                      // the map constructor
.add(object)               // method to add a layer or element

Layer()                    // the layer constructor
.add(object)               // method to add an element
.setVisibility(boolean)    // mothod to set the visibilty

Some days later I extended the Map with a method to register event handlers that I modeled after the Jquery on/off API:

.on(events, handler)       // method to register event handlers
.off(events)               // … and to unregsiter handlers

The trick with the events parameter is, that it is a string containing both an event and an optinal namespace to group the event handlers like click.namespace

A classmate then gave me the advice to remove the layer class completely and add "add()" and "remove()" methods that work like the on and off methods to group elements to layers. So the following API emerged:

.add(namespace, object)
.on(events, handler)

What I find somehow cumbersome, is, that events describe both an event and an optinal namespace, whereas namespace only describes a namespace. So

The Question is:

How to design such an API in a simple, but still consistent way so that I can group elements and event handlers in a similar manner?

  • \$\begingroup\$ This question appears to be off-topic because it is a design review and not a code review. \$\endgroup\$ – Jamal Feb 21 '14 at 18:39

Since namespaces are always optional, you can follow the common JavaScript convention and put them at the end of the arguments list:

.add(object, namespace1)
.on(events, handler, namespace2)
.on(otherEvents, handler)

As you say, events describe both an event and a namespace. More specifically, they describe an event on a namespace or the whole map, which is why it makes sense to add back the "layer" object. This is the simplest way to show the difference between "event on a layer" and "event on all layers":

var l = Layer()            // the layer constructor
.add(object)               // method to add an element
.setVisibility(boolean)    // mothod to set the visibilty
.on("click", handler)      // do XXX when clicking on an object of this layer

var m = Map()              // the map constructor
.add(l)                    // method to add a layer or element
.on("hover", handler)      // do XXX when hovering the whole map

You should also wonder what you're going to do with bubbling events. If there's an event which is not handled in the layer, is it going to bubble up and be handled by the map? For all browsers? Those issues (and many more) are already covered by jQuery, which is why I don't suggest rewriting half of their event-handling code and simply use it directly. Why not writing your API as a jQuery plugin?

  • 1
    \$\begingroup\$ I thought of namespaces more like "click.handler1" or "click.someOtherHandlers", so that it is easier to unregister and group event handlers and not like "click.layer1" or "click.layer2" to show where the event comes from (maybe i misinterpreted that part). I do not plan to handle any events on layers, only on the map itself, an event could for example be "pan" or "zoom" (it doesn't make sense to pan a single layer). Additionally i can not rely on jQuery because jQuery doesn't have any SVG functionality at all and my library will be SVG only - I just used it as an inspiration for my API. \$\endgroup\$ – taffer Mar 14 '12 at 10:14
  • \$\begingroup\$ OK, I was mistaken. Are namespaces optional for objects too? \$\endgroup\$ – Quentin Pradet Mar 14 '12 at 13:41
  • \$\begingroup\$ You mean when adding elements? Yes they should be optional, so that you can stuff elements into the map without having to group them. \$\endgroup\$ – taffer Mar 14 '12 at 14:47
  • \$\begingroup\$ I just encountered another problem: I wanted to get rid of the Layer.setVisibility() method, by using map.add() and map.remove() instead but that will mix up the order of the layers, due to SVG's painter algorithm when setting layers invisible repeatedly. \$\endgroup\$ – taffer Mar 14 '12 at 14:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.