Created
October 15, 2012 21:04
-
-
Save ivanopagano/3895471 to your computer and use it in GitHub Desktop.
Huffman Jit Visualizer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package patmat | |
/* | |
* This file should be used to generate an easy visualization of huffman trees implemented | |
* during the course of the Coursera "Principles of Functional Programming" class, held by prof.M.Odersky. | |
* | |
* It's intended as an aid to the students. | |
* Take notice that you need to have access to the course material, so it's almost useless for any other purpose. | |
* | |
* To correctly compile you need to have the patmat.Huffman object visible in your class-path. | |
* The easiest way is to include this class alongside your assignment project. | |
* | |
* To correctly visualize the output file, you need to download an unzip the excellent javascript visualization library | |
* "JavaScript InfoVis Toolkit" | |
* available from http://philogb.github.com/jit/index.html | |
* | |
* You can freely distribute and modify this software for the better | |
* Enjoy | |
* | |
*/ | |
import Huffman._ | |
import java.io.{ File, FileWriter, Writer } | |
object HuffmanViz { | |
/* | |
* You should call the application passing two parameters: | |
* 1. the absolute path to the folder where you unzipped the Javascript Infoviz Toolkit | |
* 2. the (absolute or relative) path to the destination html file. | |
*/ | |
def main(args: Array[String]) { | |
if (args.size < 2) println("""|Please specify: | |
| 1. the absolute path of the folder where I can find the Javascript Infoviz Toolkit file "jit-yc.js" | |
| 2. the path to an output .html file which will show the huffman tree | |
|""".stripMargin) | |
else { | |
//Check the destination file | |
val jitFile = args(0) | |
val dest = new File(args(1)) | |
if (dest.isDirectory() || !dest.getName().endsWith(".html")) throw new Error("The given path corresponds to a directory, please choose a valid .html filename") | |
val jsonTree: String = treeToJson(buildTree) | |
//passing the destination file, the lambda expression gives me back an auto-closing writer to the file | |
val result = withResource(dest) { writer => | |
val output = outputTemplate.format(jitFile, jsonTree, chars(buildTree).mkString.toUpperCase) | |
writer.write(output) | |
} | |
println("You can see the generated tree opening the file " + dest.getAbsolutePath()) | |
} | |
} | |
//Change this method implementation to define the code tree to visualize | |
def buildTree: CodeTree = frenchCode | |
/* | |
* A method wrapping operations with I/O to guarantee correct resource cleaning | |
*/ | |
private def withResource(file: File)(f: Writer => Unit) { | |
val writer = new FileWriter(file, false) | |
try { | |
f(writer) | |
} finally { | |
writer.close() | |
} | |
} | |
//This is the json template for each codetree node | |
private val nodeTemplate: String = """{ | |
id: "%1$s", | |
name: "(%1$s) %2$d", | |
data: {}, | |
children: [%3$s] | |
}""" | |
/* | |
* Converts the tree to a json format for the javascript infoviz library | |
*/ | |
def treeToJson(tree: CodeTree): String = tree match { | |
case Leaf(c, w) => nodeTemplate.format(c.toUpper, w, "") | |
case Fork(l, r, chars, w) => nodeTemplate.format(chars.mkString.toUpperCase, w, treeToJson(l) + "," + treeToJson(r)) | |
} | |
//This is the template for the final html file | |
private val outputTemplate = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |
<title>Huffman Trees</title> | |
<style> | |
html, body { | |
margin:0; | |
padding:0; | |
font-family: "Lucida Grande", Verdana; | |
font-size: 0.9em; | |
text-align: center; | |
background-color:#F2F2F2; | |
} | |
#container { | |
width: 1000px; | |
height: 600px; | |
margin:0 auto; | |
position:relative; | |
border: thin solid grey; | |
cursor: move; | |
background-color: white; | |
} | |
.text { | |
margin: 2px; | |
} | |
#infovis { | |
position:relative; | |
width:1000px; | |
height:600px; | |
margin:auto; | |
overflow:hidden; | |
} | |
</style> | |
<!-- If you need to include this script, it's available in the JavaScript InfoVis Toolkit bundle --> | |
<!--[if IE]><script language="javascript" type="text/javascript" src="./Extras/excanvas.js"></script><![endif]--> | |
<!-- JIT Library File --> | |
<script language="javascript" type="text/javascript" src="%s/jit-yc.js"></script> | |
<script> | |
var labelType, useGradients, nativeTextSupport, animate; | |
(function() { | |
var ua = navigator.userAgent, | |
iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i), | |
typeOfCanvas = typeof HTMLCanvasElement, | |
nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'), | |
textSupport = nativeCanvasSupport | |
&& (typeof document.createElement('canvas').getContext('2d').fillText == 'function'); | |
//I'm setting this based on the fact that ExCanvas provides text support for IE | |
//and that as of today iPhone/iPad current text support is lame | |
labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML'; | |
nativeTextSupport = labelType == 'Native'; | |
useGradients = nativeCanvasSupport; | |
animate = !(iStuff || !nativeCanvasSupport); | |
})(); | |
function init(){ | |
//init data | |
var json = %s; | |
//end | |
//init Spacetree | |
//Create a new ST instance | |
var st = new $jit.ST({ | |
//id of viz container element | |
injectInto: 'infovis', | |
//set duration for the animation | |
duration: 800, | |
//set animation transition type | |
transition: $jit.Trans.Quart.easeInOut, | |
//set distance between node and its children | |
levelDistance: 30, | |
orientation: 'top', | |
width: 0, | |
height: 0, | |
constrained: false, | |
levelsToShow: 100, | |
//enable panning | |
Navigation: { | |
enable:true, | |
panning:true | |
}, | |
//set node and edge styles | |
Node: { | |
height: 20, | |
autoWidth: true, | |
type: 'rectangle', | |
color: 'none', | |
overridable: false | |
}, | |
Edge: { | |
color: 'navy', | |
overridable: false | |
}, | |
onBeforeCompute: function(node){ | |
}, | |
onAfterCompute: function(){ | |
}, | |
//This method is called on DOM label creation. | |
//Use this method to add event handlers and styles to | |
//your node. | |
onCreateLabel: function(label, node){ | |
label.id = node.id; | |
label.innerHTML = node.name; | |
label.onclick = function(){ | |
st.onClick(node.id); | |
}; | |
//set label styles | |
var style = label.style; | |
/*style.width = 100 + 'px';*/ | |
style.width = node.name.width * 1.5 + 'px'; | |
style.height = 17 + 'px'; | |
style.fontWeight = 'bold'; | |
style.cursor = 'pointer'; | |
style.color = '#333'; | |
style.fontSize = '0.8em'; | |
style.textAlign= 'center'; | |
style.paddingTop = '3px'; | |
}, | |
onBeforePlotNode: function(node){ | |
}, | |
onBeforePlotLine: function(adj){ | |
} | |
}); | |
//load json data | |
st.loadJSON(json); | |
//compute node positions and layout | |
st.compute(); | |
st.setRoot("%s", "animate"); | |
//end | |
} | |
</script> | |
</head> | |
<body onload="init();"> | |
<div id="container"> | |
<div id="infovis"></div> | |
</div> | |
</body> | |
</html>""" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment