/**
* @brief Module for rendering an arc diagram to a svg canvas with d3
*
* @file suffixtree.cpp
* @author David Pfahler
* @author Matthias Gusenbauer
*/
var width = $('.starter-template').width(); //> width of svg image
var height = 400; //> height of svg image
var data = [];
var LoD = 1;
var transparency = 0.3;
var hoverTransparency = 1;
var isMirrored = false;
var isSmaller = false;
var fC = "lightsteelblue"
var sC = "darkslateblue"
/** Method to parse the input of the textfield or the file
* @param input The string of data to be parsed and visualized as arcs
* @return Struct of characters and essential matching pair arcs to draw
*/
function parseInput(input)
{
var characters = input.split('');
var tree = new SuffixTree(input);
// definition 1 - maximal matching pairs
var mmPairs = tree.getMaximalMatchingPairs();
// defintion 2 - get repetition regions
var regions = tree.getRepRegion(input);
// definition 3 - get essential matching pairs
var emPairs = tree.getEssentialMatchinPairs(mmPairs, regions);
return {
characters: characters,
arcs: emPairs
};
}
/** Method to calculate the correct arc height given the distance of the patterns
* @param arcs All arcs for a pattern
* @return The maximum arc height
*/
function getMaxArcHeight(arcs)
{
maxPairDistance = 0;
for(i = 0; i < arcs.length; i++)
{
currDistance = (arcs[i].targetPos - arcs[i].sourcePos + arcs[i].numberEle)/2
if(currDistance > maxPairDistance)
{
maxPairDistance = currDistance;
}
}
return Math.max(maxPairDistance,getMaxArcWidth(arcs));
}
/** Method to calculate the correct arc width given the distance of the patterns
* @param arcs All arcs for a pattern
* @return The maximum arc width
*/
function getMaxArcWidth(arcs)
{
maxPairDimension = 0;
for(i = 0; i < arcs.length; i++)
{
if(arcs[i].numberEle > maxPairDimension)
{
maxPairDimension = arcs[i].numberEle;
}
}
return maxPairDimension;
}
/** Draw the arc diagram
*/
function draw(){
// clear the chart and redraw everything
$("#chart").empty();
arcs = [];
mirroredArcs = [];
if(!isSmaller)
mirroredArcs = data.arcs;
//filter the data for LoD
for(j = 0; j < data.arcs.length; j++)
{
if(data.arcs[j].numberEle >= LoD)
arcs.push(data.arcs[j]);
else if(isMirrored && isSmaller)
mirroredArcs.push(data.arcs[j]);
}
var numElements = data.characters.length;
var fontWidth = width / Math.max(numElements,1);
var fontHeight = fontWidth*1.2;
var x = d3.scale.linear()
.domain([0,numElements])
.range([0,width]);
height = (getMaxArcHeight(arcs) + 1)* fontHeight;
upperArcLine = height - fontHeight;
if(isMirrored)
{
var mirroredArcHeight = getMaxArcHeight(mirroredArcs) * fontHeight;
height = height + mirroredArcHeight;
}
var colour = d3.scale.linear()
.domain([0,getMaxArcWidth(arcs)])
.range([fC,sC]); // nice coloring
// create new chart with the specified width and height
var chart = d3.select("svg")
.attr("width", width)
.attr("height", height);
var textGroup = chart.append("g")
.attr("id","textGroup");
var textPlot = textGroup.selectAll("g");
//plot the characters along the x-axis
if(fontWidth > 3)
{
textPlot = textGroup
.selectAll("g")
.data(data.characters)
.enter()
.append("g")
.attr("transform", function(d,i) {
x1 = i * fontWidth;
y1 = upperArcLine;
return "translate(" + x1 + "," + y1 + ")";
})
.attr("id",function(d,i){return i;});
textPlot.append("text")
.attr("y",fontHeight/2)
.attr("x",fontWidth/2)
.attr("style","font-size:"+fontWidth+'px')
.text(function(d) {return d;});
}
//plot the arcs like defined in the arcs array of the parsed data
var arcGroup = chart.append("g")
.attr("id","arcGroup");
var mirroredArcGroup = chart.append("g")
.attr("id","mirroredArcGroup");
arcGroup.selectAll("path")
.data(arcs)
.enter().append("path")
.style("stroke-opacity",transparency)
.attr("d",function(d,i){
patternCenterDistance = (d.numberEle*fontWidth)/2;
x1 = x(d.sourcePos) + patternCenterDistance;
x2 = x(d.targetPos) + patternCenterDistance;
y = upperArcLine-6;
arcCenter = (x2 - x1)/2;
return "M" + x1 + ","+y+" A "+ arcCenter +","+ arcCenter +" 0 0 1 " + x2 + ","+y;
})
.attr("stroke", function(d,i){return colour(d.numberEle);})
.attr("stroke-width",function(d,i){return d.numberEle*fontWidth;})
.on("click",function(d){
arcGroup
.selectAll("path")
.style("stroke-opacity",function(x){if(d.text==x.text) return hoverTransparency; else return transparency;});
})
.on("mouseover", function(d){
arcGroup
.selectAll("path")
.style("stroke-opacity",function(x){if(d==x) return hoverTransparency; else return transparency;});
textPlot
.select("text")
.style("fill-opacity",function(x,n){
if( (n >= d.sourcePos && n < d.sourcePos + d.numberEle) ||
(n >= d.targetPos && n < d.targetPos + d.numberEle))
return hoverTransparency; else return transparency;});
tooltip.style("visibility", "visible").text(d.text);
return 1;
})
.on("mousemove", function(){
bb = tooltip.node().getBoundingClientRect();
w = d3.event.pageX-bb.width/2;
h = d3.event.pageY-bb.height - 13;
return tooltip
.style("top", h+"px")
.style("left",w+"px");})
.on("mouseout", function(){
arcGroup
.selectAll("path")
.style("stroke-opacity",transparency);
textPlot
.select("text")
.style("fill-opacity",hoverTransparency);
return tooltip.style("visibility", "hidden");
});
if(isMirrored)
{
mirroredArcGroup.selectAll("path")
.data(mirroredArcs)
.enter().append("path")
.style("stroke-opacity",transparency)
.attr("d",function(d,i){
patternCenterDistance = (d.numberEle*fontWidth)/2;
x1 = x(d.sourcePos) + patternCenterDistance;
x2 = x(d.targetPos) + patternCenterDistance;
y = upperArcLine+fontHeight/2 + 6;
arcCenter = (x2 - x1)/2;
return "M" + x1 + ","+y+" A "+ arcCenter +","+ arcCenter +" 0 1 0 " + x2 + ","+y;
})
.attr("stroke", function(d,i){return colour(d.numberEle);})
.attr("stroke-width",function(d,i){return d.numberEle*fontWidth;})
.on("click",function(d){
arcGroup
.selectAll("path")
.style("stroke-opacity",function(x){if(d.text==x.text) return hoverTransparency; else return transparency;});
mirroredArcGroup
.selectAll("path")
.style("stroke-opacity",function(x){if(d.text==x.text) return hoverTransparency; else return transparency;});
})
.on("mouseover", function(d){
mirroredArcGroup
.selectAll("path")
.style("stroke-opacity",function(x){if(d==x) return hoverTransparency; else return transparency;});
arcGroup
.selectAll("path")
.style("stroke-opacity",function(x){if(d==x) return hoverTransparency; else return transparency;});
textPlot
.select("text")
.style("fill-opacity",function(x,n){
if( (n >= d.sourcePos && n < d.sourcePos + d.numberEle) ||
(n >= d.targetPos && n < d.targetPos + d.numberEle))
return hoverTransparency; else return transparency;});
tooltip.style("visibility", "visible").text(d.text);
return 1;
})
.on("mousemove", function(){
bb = tooltip.node().getBoundingClientRect();
w = d3.event.pageX-bb.width/2;
h = d3.event.pageY-bb.height - 13;
return tooltip
.style("top", h+"px")
.style("left",w+"px");})
.on("mouseout", function(){
mirroredArcGroup
.selectAll("path")
.style("stroke-opacity",transparency);
arcGroup
.selectAll("path")
.style("stroke-opacity",transparency);
textPlot
.select("text")
.style("fill-opacity",hoverTransparency);
return tooltip.style("visibility", "hidden");
});
}
}
// Figure 1: 28746391473564827639137
// Figure 2: 1234567abcde1234567fghij1234567
// Figure 3: 1010101010101010
// Figure 4: abcd111110000011111abcd
// Figure 5: 11111000110111001001011110001101110001010