indexpost archiveatom feed syndication feed icon

Reading Comprehension and Color

2016-12-04

I have been working in Trac lately and while the general experience has been a positive one I have been troubled by some of the design decisions in the default styling and its impact on my reading comprehension. I set about fixing the failings I perceived and got to thinking more broadly in the process.

The Problem

Trac is a issue tracker, a wiki and a source control interface. My impression of it is that it mostly does as it says on the tin with few surprises. However, the default style settings have been proving to be a nagging problem on things like issue comments. Longer discussions are hard to follow when there are several participants, or one person responds to their own comment. This is partly due to how low the contrast is and how small the font is by default.

What Does It Look Like?

nprescott@… commented 18 days ago
jdoe@… commented 21 hours ago
jdoe@… commented 21 hours ago
owilde@… commented 6 hours ago

While Trac lets administrators write or apply custom stylesheets, it would be foolish to try to convince everyone I work with to acclimate to a new interface solely because of an "issue" I perceive.

A Solution

My solution has been to try and add context to each commenter, or conversation participant from the client-side with Grease Monkey. I considered simply applying a custom stylesheet with something like Stylish but decided the results would improve readability but do nothing to aid in comprehension.

Example of the Result

nprescott@… commented 18 days ago
jdoe@… commented 21 hours ago
jdoe@… commented 21 hours ago
owilde@… commented 6 hours ago

How It Is Accomplished

The whole thing works pretty simply. I parse out the commenter username, and then create an hash1 from that string. I convert the hash to a hexadecimal string and then take a 6 character substring. This 6 hexadecimal character string becomes the HTML background-color for that username/comment header.

The whole thing is written as such:

String.prototype.hashCode = function () {
    var hash = 0,
        i,
        chr,
        len;
    if (this.length === 0) return hash;
    for (i = 0, len = this.length; i < len; i++) {
        chr = this.charCodeAt(i);
        hash = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
    }
    return hash;
};

const parseNames = /\s(\w+)@…$/;

window.onready(function () {
    for(let node of document.querySelectorAll('h3.change')) {
        let [name, _] = node.innerText.match(parseNames);
        let hexString = name.hashCode().toString(16).substr(1, 6);
        node.style = `background-color: #${hexString}; color: white;`;
    }
}())

I opted for some poorly supported ES6 because, to my knowledge Grease Monkey is already Firefox only and I like the concision of tuple unpacking and for...of loops. The hashCode method isn't very robust, but the driving factor was both speed and simplicity. I'm suprised there isn't something built-in to the language to support this, but I may have missed something in the quick research I did.

Similar Projects

Synesthesia is an interesting script I was recently linked to. It's designed to uniquely colorize the results of a text stream for those things matching a given regular expression.

Identicons are an obviously similar project (think default GitHub avatars). They actually capture more information but this is less important in my case due to the potential number of unique usernames that I am working within.

Thoughts

One interesting result of all of this has been how I read the comments on issues. Because each name is hashed the same across Trac, the text of the names have lost some of their importance. It is less important that "nprescott commented: I saw this in testing yesterday" and I instead read "green said; blue replied; blue followed up..." which seems like less of a cognitive load. It was an interesting side-effect that gives me some perspective on how our brains can leverage context and how to ease the cognitive load present within user interfaces.


  1. I cheated a bit here when I realized that JavaScript doesn't expose a hash function in the same way that Python does (where the function is creatively named hash and is used for keying dictionary and sets). The above hashCode method was pulled from StackOverflow.