I made a fiddlefiddle implementing (essentially) above ideas outlined by iman. Here is how it looks when you mouse over the second ipsum in return ipsum*ipsum - ...
Here is the main portion of the code from the fiddle:
function initCodeContainer(sourceString){
codeSpans = {};
activeSpan = null;
while (codeContainer.lastChild) { codeContainer.removeChild(codeContainer.lastChild); }
ast = esprima.parse(sourceString, {range: true, sourceType: 'script'});
analysis = escope.analyze(ast);
var positionsObj = {};
positionsObj[0] = null;
positionsObj[sourceString.length] = null;
estraverse.traverse(ast, {
enter: function(node, parent){
positionsObj[node.range[0]] = null;
positionsObj[node.range[1]] = null;
}
});
var positions = Object.keys(positionsObj).map(function(p){ return +p; });
var i;
for (i=0; i<positions.length-1; i++){
var startPos = positions[i];
var endPos = positions[i+1];
var codePortion = sourceString.slice(startPos, endPos);
var span = document.createElement('span');
span.textContent = codePortion;
codeContainer.appendChild(span);
span.dataset.sourceFrom = startPos;
span.dataset.sourceTo = endPos;
span.addEventListener('click', spanClick);
span.addEventListener('mouseenter', spanMouseEnter);
codeSpans[startPos] = span;
}
while (swatchesParent.lastChild) { swatchesParent.removeChild(swatchesParent.lastChild); }
for (i=0; i<analysis.scopes.length; i++){
if (i >= colors.length){
colors[i] = generateColor(i);
}
var div = document.createElement('div');
div.classList.add('swatch');
div.style.backgroundColor = colors[i];
div.textContent = i;
swatchesParent.appendChild(div);
}
}
howHow it works