As you may have seen I’m back from vacations and trying to organize a little bit the code for the next version of the JavaScript InfoVis Toolkit, which is not there yet; although I did push the new visualizations over to GitHub so you can play with them
I also created a new project at GitHub that’s called DOMTreeMap. DOMTreeMap is a robust, library agnostic, JavaScript/HTML/CSS TreeMap library that allows you to easily create Squarified, Strip and SliceAndDice TreeMap layouts by using JSON input data. The only global object created by this library is TM and it consists on four main sub-objects/classes:
TM.Util contains useful JSON Tree manipulation methods.
TM.Squarified creates Squarified TreeMap tilings.
TM.Strip creates Strip like tilings.
TM.SliceAndDice creates Slice and Dice TreeMap tilings.
Each tiling algorithm has its pros and cons. The main criteria for determining if a tiling algorithm is good is to check for the aspect ratio of nodes, check if the result is ordered or not and check for stability (i.e whether the nodes maintain their relative positions when the TreeMap is being navigated).
Here’s a picture describing these points for the Strip, Squarified and SliceAndDice tiling algorithms:
As you may have noticed, DOMTreeMap is a standalone version of the JIT TreeMap component.
So why do this, then?
Well, I decided that for the next version of the library TreeMaps are going to be Canvas based. I’m already adapting the TreeMap tiling algorithms to render on Canvas and also plugging the rest of the TreeMap visualizations to an abstract Graph class that is also used by all other visualizations so I can use a lot of library code related to Tree Operations, Tree Animations, etc.
Also, not all TreeMap visualizations render nodes as rectangles. Some TreeMap implementations are based on Voronoi Tessellations for example:
So in order to maintain a more “abstract” notion of TreeMaps I think that having Canvas based TreeMaps would be a good idea. Anyway, now I’m working on adapting the code to be able to render TreeMaps on canvas, I must say that performance-wise things are looking promising:
You are welcome to participate on the DOMTreeMap project which will grow as a standalone solution for drawing TreeMaps solely based on HTML, CSS and JavaScript.
Just a quick post to thank everybody at the Informatics Research Laboratory for inviting me to the Parisian Seminar on InfoVis and HCI. I hope you liked my presentation . Here are the slides if anyone’s interested:
I’ll be speaking about Using Web Standards to create Interactive Data Visualizations for the Web. Here’s the abstract:
What is the best way to render complex information on the Web? The Document metaphor has been used for years in Web Standards to define the best way to show information on the Web. Today, Web Documents are turning into full fledged Web Applications and a Web Standards revolution is taking place to provide richer ways to present complex data. HTML is covering new patterns as Drag and Drop and 2D graphics; CSS is now covering transforms and animations, and JavaScript just got 100% faster. Web Standards are important because they are built natively in Web Browsers providing common functionality guidelines, independence from third-party libraries, and high interoperability with other Web components. The JavaScript InfoVis Toolkit is a toolkit for Information Visualization built solely on Web Standards. This Toolkit provides many visualization techniques to seamlessly integrate Interactive Data Visualizations in Web Pages, turning them into Web Applications. In this talk I’d like to present an overview of the new features in Web Standards and also some concepts behind the making of the JavaScript InfoVis Toolkit, as well as some user applications..
You can find more information about this talk and how to get there here. Everyone’s invited!
I like to see language implementors (or creators in this case) talk about the design challenges or choices they’re facing with in the next version of their languages.
In this video Brendan Eich, the creator of JavaScript, talks about the ES 3.1/4/5 thingy and also explains what features will be added to JavaScript in some near future (at least for the ECMA standard).
I’ll add a couple of comments about the JS features I liked below the video.
New stuff I liked about the language
Most of the things I liked about the new features of the language are related to Meta-Programming. These new features describe new behaviors in object properties, like getters and setters, but they are also related to object and property mutability, configuration, visibility, etc.
Getters and Setters
Getters and Setters were implemented by B.E. more than nine years ago at mozilla, but a new syntax is introduced in the standard by adding a static function to the Object class.
In this example the defineProperty static method of the Object class adds the length property to the obj object. The get and set methods will be called when accessing or modifying the length property. Object.getOwnPropertyDescriptor retrieves the property descriptor of the defined property.
Defining Methods and Richer Property Descriptors
The Object.defineProperty method can also be used to define instance methods:
If configurable=true, the property will be enabled for deletion or to be changed in other ways.
You can set a property to be non-enumerable by setting enumerable=false, and it won’t be detected in a for in loop (or in any other “prop” in obj expression). This means that for example we could augment Object.prototype with methods without having to iterate through them in a for in loop.
The writable property if setted to false won’t allow you to change the value of that property.
Object.create
Still no support is added for classical inheritance patterns (which makes me happy I must confess).
Instead, the differential inheritance pattern gets a function that had (somewhat) been implemented by frameworks like Closure, MooTools and others with the inherits and $merge functions. Object.create can be used for implementing prototypical inheritance: you can create a new class A that inherits from B by cloning an object and augmenting it with a Properties object. For example:
var Person = function() {};
Person.prototype.eat = function() {
alert("eating");
};
//Ninja extends Person
var Ninja = function() {};
Ninja.prototype = Object.create(Person.prototype, {
doKungFu: function() {
alert("wootoo");
}
});
var n = new Ninja();
n.eat(); //eating
n.doKungFu(); //wootoo
However, don’t forget to instantiate the superclass in your subclass constructor:
Mutability is nice but sometimes we need to make our objects immutable for design reasons, for security reasons. These methods change the mutability level of an object.
Object.preventExtensions prevents an object from extending (i.e adding new properties to it). Still the properties it has can be deleted and their value can be changed.
Object.seal does everything Object.preventExtensions does and also sets configurable=false for its properties, so they can’t be deleted. The Object properties can be changed though.
Object.freeze makes the object completely immutable. Object.freeze does the same Object.preventExtensions and Object.seal do but also sets writable=false for all object properties.
I hope this was useful to you. There are a lot more interesting language features to come, so you can read the ECMA draft if you’re interested in knowing more about this new version.
Currently the Group has 265 members and more than 1000 messages.
About Searching the Google Group
Sometimes searching via Google Web can lead to more pertinent results than searching in the Group. So if searching for “hypertree labels” in the group doesn’t give you pertinent results you can always try:
…people would tell me about the projects they do with the JIT, either at the google group, or by mail. I’m very curious about the true potential of this library, and I’d like to know more about where and how it’s used. It’s disappointing to learn about JIT projects by chance.
A Sunburst visualization is a radial space-filling visualization technique for displaying tree like structures. There are other space-filling visualization methods that use other visual encodings for describing hierarchies. For example, the Treemap is a space-filling visualization that uses “containment” to show “parent-child” relationships.
There are a couple of subtle changes that can improve the way the information is communicated by this visualization.
The “classic” Sunburst visualization uses horizontal labels for node names. One problem with this is that as I mentioned in a previous post labels can be occluded. One solution for this is to rotate labels in a way that they’re not occluded.
A simple yet important thing to do when rotating labels is to rotate the labels in a way that they’re always facing up.
In this example some labels are upside-down:
A simple check could make labels more readable:
Another interesting thing that can be used with the Canvas Text API is the maxWidth parameter. This is an optional parameter that can be used to try to force the text to fit some width. I use this parameter when plotting the Sunburst visualization:
Node Styling and Behavior
The visualization also implements events for hovering and clicking nodes. You can also provide any number of styles to be smoothly updated when hovering and clicking nodes. There’s also onClick and onHover callbacks that are called when a node is clicked or hovered respectively.
For example, this is the configuration I used in the previous example:
Node styling and tool-tips can be attached to DOM elements (like HTML or SVG labels) or they can also be attached to the Canvas. The latter method uses an internal MouseEventManager to calculate the position of the mouse event and determine which node of the graph is being hovered or clicked.
Collapsing and Expanding Subtrees
I’ve been also implementing animations for collpasing/expanding subtrees:
The collapsing process reduces the angle span occupied by a parent node and sets its children alpha value to zero. There’s also a visual mark set for collapsed nodes.
I hope you like this visualization. There’s still much work to do, mostly regarding browser compatibility. I’ll keep you up to date with the progress of this visualization and the next visualization I’ll be implementing in the next post
I’m currently working on three new visualizations for the JavaScript InfoVis Toolkit that will be added in version 1.2.
I started the development of these new visualizations a couple of weeks ago, and while trying to incorporate these new visualizations harmoniously into the Toolkit I’ve found myself considering new design and code abstractions I haven’t thought about before. That’s good for the Toolkit, and also good for my brain
One of the visualizations I’ll be incorporating in the next major release is a Force-Directed visualization. I first want to thank Marcus Cobden for donating a lot of code related to this algorithm that you can find here.
My code is based in his donation and also in a nice overview of Force-Directed layout algorithms that I’ve found here.
So what are Force-Directed Layout Algorithms?
Force-Directed Layout algorithms are graph drawing algorithms based only on information contained within the structure of the graph itself rather than relying on contextual information. The most straightforward Force-Directed algorithm uses repulsive forces between nodes and attractive forces between adjacent nodes. This physical model produces some local minima in which the graph, well, gets to a stable configuration and is drawn in an aesthetically pleasing way.
The main algorithm consists on a main loop that simulates the system for some iterations and then plots the graph. The system will consist on repulsive forces between all graph nodes and attractive forces between adjacent nodes. The force models considered correspond to Hooke’s law and Coulomb’s law.
Here’s an example with some JSON data I also use for other examples at the demos page:
There are lots of refinements and different methods for making Force-Directed Layouts. Some are just based on the model I described before, others are based on what’s called Graph Theoretic Distances: If for two adjacent nodes their ideal distance is set as d, then for nodes with shortest path distance of n their ideal layout distance should be n * d. Attractive and repulsive forces are used to make a graph system with random nodes positions get to a local minima based on these rules.
I implemented the first model I described. For each iteration the computePositionStep method is called to update all nodes positions based on attractive and repulsive forces. The formal parameters passed to the method are property which is an array of node properties which contain positions to be updated and opt which is an object containing layout options like generic repulsive and attractive force functions. $C creates a new Complex Number.
computePositionStep: function(property, opt) {
var graph = this.graph, GUtil = Graph.Util;
var min = Math.min, max = Math.max;
var dpos = $C(0, 0);
//calculate repulsive forces
GUtil.eachNode(graph, function(v) {
//initialize disp
$each(property, function(p) {
v.disp[p].x = 0; v.disp[p].y = 0;
});
GUtil.eachNode(graph, function(u) {
if(u.id != v.id) {
$each(property, function(p) {
var vp = v.getPos(p), up = u.getPos(p);
dpos.x = vp.x - up.x;
dpos.y = vp.y - up.y;
var norm = dpos.norm() || 1;
v.disp[p].$add(dpos
.$scale(opt.nodef(norm) / norm));
});
}
});
});
//calculate attractive forces
var T = !!graph.getNode(this.root).visited;
GUtil.eachNode(graph, function(node) {
GUtil.eachAdjacency(node, function(adj) {
var nodeTo = adj.nodeTo;
if(!!nodeTo.visited === T) {
$each(property, function(p) {
var vp = node.getPos(p), up = nodeTo.getPos(p);
dpos.x = vp.x - up.x;
dpos.y = vp.y - up.y;
var norm = dpos.norm() || 1;
node.disp[p].$add(dpos.$scale(-opt.edgef(norm) / norm));
nodeTo.disp[p].$add(dpos.$scale(-1));
});
}
});
node.visited = !T;
});
//arrange positions to fit the canvas
var t = opt.t, w2 = opt.width / 2, h2 = opt.height / 2;
GUtil.eachNode(graph, function(u) {
$each(property, function(p) {
var disp = u.disp[p];
var norm = disp.norm() || 1;
var p = u.getPos(p);
p.$add($C(disp.x * min(Math.abs(disp.x), t) / norm,
disp.y * min(Math.abs(disp.y), t) / norm));
p.x = min(w2, max(-w2, p.x));
p.y = min(h2, max(-h2, p.y));
});
});
}
You can find more information about this algorithm in this overview of Force-Directed algorithms.
This method is called multiple times to provide a final layout, for example like this:
Where times corresponds to the number of iterations of the simulation, and is generally > 50 and t can be thought as the global temperature of a system that gets cooler with each iteration.
Performance
Although there are a couple of methods to reduce the complexity of this algorithm, this implementation runs like O(V^3), which can be considered as really bad performance.
This is not desirable for real-time interactive visualizations, in which everlasting computation algorithms can lead to blocking browser popups like “This Script is Taking too long…” or things like that.
One way you can avoid these popups is by making incremental computations. This can be done by splitting the main algorithm that has for example 100 iterations into smaller pieces of 20 iterations each. The main iteration loop could then be changed into something like this:
And the main computation would be split into smaller parts calling on each step of the computation the onStep callback.
Graph Operations
For graph operations (Adding/Removing nodes and edges, Graph Sum and Graph Morphing) I make all iterations in the first layout and then only apply 20 iterations after some operation has been completed. Here's a video:
When (*not*) to use Force-Directed Layouts
Force-Directed Layouts can be a good choice when you're drawing general graphs and you don't have domain specific (or any other topological) information about them.
Tree structures however are a special case of graphs: this means that tree structures have more constrains and therefore there's more contextual information for drawing a Tree than for drawing a general graph.
Also, Trees are easier to grasp for the human eye than "general graphs". There's that intrinsic notion of hierarchy that can be used to draw aesthetically pleasing graph layouts. Think about the "general graph" layouts that start with the drawing of a spanning tree and then add the "extra edges" to complete the graph structure (for example here and here). The Multitrees method I mentioned a couple of posts ago was also developed to try to extract more contextual information about a graph and draw it based on a notion of partial hierarchy.
Because of this, in my opinion, it wouldn't be wise to plot Trees that have many nodes with this Force-Directed algorithm: this extra-information about trees isn't used in this layout. However, if you're planning on drawing general graphs and you don't have any other information about them, then this algorithm can detect interesting symmetries and make aesthetically pleasing drawings.
I'll keep you updated with the other visualizations I'm working on in the next posts.
As you might know, the JavaScript InfoVis Toolkit uses the HTML5 Canvas element for plotting and animating graphs. This is all very nice, Canvas performance compared to other techniques for plotting these things (SVG for example) is by far superior. But of course, there are drawbacks.
Canvas better performance is due to the fact that there are no tracked elements: the Canvas is simply an image and you’re drawing there just like you’d be drawing something in paint. One big problem is that there’s no native possibility to add events to what’s drawn in Canvas, like a plotted node, edge or label.
As opposed to Canvas, SVG has a DOM/XML like spec: you have all these tags (<g> <text> <rect>) and each of them is just like a DOM element: you can add click event handlers, individual styling with CSS, etc.
Having to keep track of all these elements and handling a DOM-tree makes the performance of SVG not suitable for visualizing (and animating) medium to large datasets on the web.
Using HTML labels
Just like SVG, HTML is a DOM/XML-like spec, where you can add event handlers to each element. Also, every web developer knows HTML so exposing HTML labels through user-defined controller methods in the library seemed to me like a good choice. For controller methods like onCreateLabel or onPlaceLabel an HTML element is passed and the user can style or add event-handlers to it.
For example, here’s a fragment of the code used in the RGraph demo. You can see the rest of the code here:
//Add the name of the node in the correponding label
//and a click handler to move the graph.
//This method is called once, on label creation.
onCreateLabel: function(domElement, node){
domElement.innerHTML = node.name;
domElement.onclick = function(){
rgraph.onClick(node.id);
};
},
//Change some label dom properties.
//This method is called each time a label is plotted.
onPlaceLabel: function(domElement, node){
var style = domElement.style;
style.display = '';
style.cursor = 'pointer';
if (node._depth <= 1) {
style.fontSize = "0.8em";
style.color = "#ccc";
} else if(node._depth == 2){
style.fontSize = "0.7em";
style.color = "#494949";
} else {
style.display = 'none';
}
var left = parseInt(style.left);
var w = domElement.offsetWidth;
style.left = (left - w / 2) + 'px';
}
In my opinion this is a good approach, good points are:
I'm using well known HTML elements.
Dealing with DOM elements let's you add event handlers, individual styling and things like that.
Weak points are:
I'm using a DOM tree, which means that if labels are plotted at all times I'm exhaustively updating the DOM and this might lead to performance problems.
HTML is good for structuring pages, but for example you might want to apply transformations to HTML elements (like rotating labels, etc), and these aren't supported by all browsers yet.
So one of the problems that might arise is, for example, the fact that in radial layouts labels might be occluded:
Using SVG labels
So I began exploring other possibilities to create labels. For this I abstracted the Label interface I had and split it into:
Graph.Label.Native (for native canvas labels)
Graph.Label.DOM(abstract class for dom elements)
Graph.Label.HTML(extends the DOM interface with HTML specific stuff)
Graph.Label.SVG(extends the DOM interface with SVG specific stuff)
I also modified the Canvas class so you can specify the type of labels you want to use, labels:'HTML', labels:'SVG' or labels:'Native'. Default's HTML.
The same RGraph example code now would look like this:
//Add the name of the node in the correponding label
//and a click handler to move the graph.
//This method is called once, on label creation.
onCreateLabel: function(domElement, node){
domElement.firstChild
.appendChild(document
.createTextNode(node.name));
domElement.onclick = function(){
rgraph.onClick(node.id, {
hideLabels: false
});
};
},
//Change some label dom properties.
//This method is called each time a label is plotted.
onPlaceLabel: function(domElement, node){
var bb = domElement.getBBox();
if(bb) {
//center the label
var x = domElement.getAttribute('x');
var y = domElement.getAttribute('y');
//get polar coordinates
var p = node.pos.getp(true);
//get angle in degrees
var pi = Math.PI;
var cond = (p.theta > pi/2 && p.theta < 3* pi /2);
if(cond) {
domElement.setAttribute('x', x - bb.width );
domElement.setAttribute('y', y - bb.height );
} else if(node.id == rgraph.root) {
domElement.setAttribute('x', x - bb.width/2);
}
var thetap = cond? p.theta + pi : p.theta;
domElement.setAttribute('transform', 'rotate('
+ thetap * 360 / (2 * pi) + ' ' + x + ' ' + y + ')');
}
This code does a little bit more than just plotting the label, it rotates the labels so they're not occluded:
Good points of this approach are:
Just like with any other DOM element, you can add event handlers.
You can apply transformations to labels.
Weak points:
Performance, for the same reasons as HTML.
IE does not support SVG.
Bonus good point: Google is making work SVG in IE with some open source library that works apparently the same as the ExCanvas library. Here's the Open Source project that will be presented here.
That's like the main reason why I've been considering a different approach for labels
Native Canvas labels
Native Canvas labels make use of the HTML5 Canvas text API to plot labels.
Since the labels are just painted in the Canvas there's no DOM tree to update, and performance is good.
The Canvas text API has fillText, strokeText and measureText as methods. You can read more about the Canvas Text API here.
This is the code I added to the Graph.Label.Native class:
Graph.Label.Native = new Class({
plotLabel: function(canvas, node, controller) {
var ctx = canvas.getCtx();
var coord = node.pos.getc(true);
ctx.fillText(node.name, coord.x, coord.y);
},
hideLabel: $empty
});
A very good point about this approach is performance. Also, the code is simpler. You don't have to keep a labelContainer and update DOM labels each time you're making an animation.
Weak points are:
Opera does not support this feature.
You can't natively add event handlers to labels. I think I've seen someone do something similar for text in processing, but I'm not sure there's a good way of doing this without keeping track of the position of each label and perform a check each time a click is triggered in the canvas element.
I should change the way I define controller methods, in order to be able to pass a custom label object with x, y, theta, rho, width, height properties that could be modified on the fly, and then translate these changes into translate and rotate native canvas calls to be able to plot the text the way the user wants it. This seems just to damn complicated.... But I'll consider it.
Anyway, these are the methods I've found to plot labels into graphs.
Which one do you think is the best?
Do you know about any other approaches I could take to solve this problem?
I just tagged the JavaScript InfoVis Toolkit with version 1.1.3. It’s been some time since the last release, and I wanted to use this post to make a summary of the changes and to describe some of the new features that have been added to the library.
I’ll start with the new features:
SpaceTree: SwitchAlignment
I added some new global configuration properties to the SpaceTree: align and indent.
Align sets the alignment of the tree to center, left and right:
The indent parameter sets an offset between a parent and its children when the alignment is left or right. You can also use the switchAlignment method for changing the alignment of the tree with an animation.
SpaceTree: Multiple nodes in path
I added two new methods to the SpaceTree: addNodeInPath and clearNodesInPath.
These two methods allow you to add a node to the “selected-nodes” path. When a node belongs to the “selected-nodes” path it remains always visible (as in always expanded).
I made this small video to show the feature:
SpaceTree: MultiTree
I added a SpaceTree configuration property called multitree.
If multitree=true, the visualization will search for the $orn data property in each node and display the subtrees according to their orientation.
In this example I set multitree=true and set $orn=’left’ for some nodes and $orn=’right’ for others. This way I create a partition of the tree:
I also use the setRoot method to set the clicked node as root for the visualization. This way the clicked node is centered and a centrifugal view from that node is drawn.
Bug Fixes
I’ve been fixing a couple of bugs also, most of them have to do with Treemaps:
Most of us JavaScript developers can’t work without using a JavaScript Library/Framework today. JavaScript is a very nice language, but it requires for you to write a lot of code before you can implement some interesting animation, drag and drop feature, or Ajax request/polling.
This is in part due to the fact that every line of code we write must be browser compatible, and that adds lots of “ifs” to our code.
So I guess it’s understandable to think that choosing a framework that can abstract these kind of things for us is good. By using a framework we can concentrate on other kind of problems, more like high-level-usability-pattern problems.
Some frameworks stick with JavaScript as their main language (like MooTools or JQuery). Other frameworks simply let you type another kind of language that then gets compiled into JavaScript. I guess that having a language with built-in classical inheritance syntax and a nice IDE to support it are good reasons to develop these kind of libraries that translate some code into another.
Frameworks are undeniably good, but most of the things I learn about the JavaScript programming language were learn while hacking some pure JavaScript code.
When hacking pure JavaScript code you find yourself hacking common language idioms that are usually abstracted by frameworks. And it’s nice to understand how these things work. When you get how a specific JavaScript pattern/idiom works you get to understand lots of things about the language itself.
Most of the people don’t do this today. You can see posts about call and apply, closures and private members patterns very often in Reddit and Ajaxian, and each time that post appears lots of other people upmod it. So that means that most of the people today probably use the bind Function method without really knowing what it does.
The worst part is that JavaScript is a very beginner-friendly language, a good start for people not having a computer sicence related background, but at the same time there are lots of things about the language itself that are advanced features (object mutability, booleans as defaults, functions as first class citizen, prototypal inheritance) and most of the users are never aware of these features, most of the time due to the abstraction of the frameworks they’re using.
An Example
This is a very simple example (and interesting interview question also).
If you’re dealing with the dom when hacking JavaScript then you might often use the hasClass and removeClass methods from JQuery, MooTools, or whatever.
So, how would you write them?
function hasClass(domElement, className) {
//code here...
}
function removeClass(domElement, className) {
//code here...
}
Please, if you’re reading this, take five minutes of your time and write these functions out before reading the answers. Believe me, it’s worth the effort. I mean, how much time can it take?
Basically we add one space at the beginning and end of each string, and see if the className property of the domElement contains the className string provided.
Why adding those spaces? Well, if we don’t add spaces then we could have problems with names containing the given className.
Also, the code is concise and most of the work is done by the built-in indexOf method, which is good for performance.
Did you get that answer well? Good! How about your removeClass function?
I think this RegExp is better explained with an example. Lets say that:
var className = 'myclassname';
domElement.className = 'myclassname yeah';
removeClass(domElement, className);
Then the RegExp will be
'(^|\\s)myclassname(?:\\s|$)'
Lets make it simpler first:
'(^|\\s)myclassname(\\s|$)'
Ok, so that’s simple enough.
So this regexp means that either we’re at the beginning of the string (^) and searching for our className having a space at the end (‘^myclassname\\s’) or simply ending with that className (‘^myclassname$’) or we’re looking for our className string having a space at the beginning and end (‘\\smyclassname\\s’) or we’re at the end of the string looking for our className having (or not) a space at the beginning of the string (‘\\smyclassname$’ or ‘^myclassname$’).
This regexp is equivalent to (if we had startsWith and endsWith methods):
Ok, so once the RegExp matches it’s replaced by ‘$1′, which means the first capturing group, in this case the (^|\\s) group.
So back to our example, the domElement.className was: ‘myclassname yeah’ so the RegExp that matches is ^myclassname\\s and the capturing group is ^, so the returned string is ‘yeah’, just as espected.
What (?: …) does is not to make a capturing group from the parenthesis match. I think this is good for performance f you’re not using that group in the string replacement:
Non-Capturing Parentheses are of the form `(?:<regex>)’ and facilitate grouping only and do not incur the overhead of normal capturing parentheses. They should not be counted when determining numbers for capturing parentheses which are used with backreferences and substitutions. Because of the limit on the number of capturing parentheses allowed in a regex, it is advisable to use non-capturing parentheses when possible.
Conclusion
These methods could have probably been written differently if disk space and performance weren’t such an important issue in JavaScript, but with those constraints even the most trivial methods like hasClass and removeClass can be interesting to read.
So this is my recommendation: try to understand how things you normally use are implemented. There are lots of interesting JavaScript libraries that make excellent code that’s performant and save disk space (:P) so check them out, you might learn about lots of things, even the most simple functions can have interesting concepts.
Hello there, I'm Nicolas Garcia Belmonte, a Computer Science Engineer from the Buenos Aires Institute of Technology, in Argentina. I live in France now.