166 lines
21 KiB
JavaScript
166 lines
21 KiB
JavaScript
|
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);
|
||
|
})();
|
||
|
|
||
|
var Log = {
|
||
|
elem: false,
|
||
|
write: function(text){
|
||
|
if (!this.elem)
|
||
|
this.elem = document.getElementById('log');
|
||
|
this.elem.innerHTML = text;
|
||
|
this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
function init(){
|
||
|
//init data
|
||
|
var json = "{\"children\": [{\"children\": [{\"children\": [], \"data\": {\"playcount\": \"276\", \"artist\": \"A Perfect Circle\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/11403219.jpg\", \"$area\": 276}, \"id\": \"album-Thirteenth Step\", \"name\": \"Thirteenth Step\"}, {\"children\": [], \"data\": {\"playcount\": \"271\", \"artist\": \"A Perfect Circle\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/11393921.jpg\", \"$area\": 271}, \"id\": \"album-Mer De Noms\", \"name\": \"Mer De Noms\"}], \"data\": {\"playcount\": 547, \"$area\": 547}, \"id\": \"artist_A Perfect Circle\", \"name\": \"A Perfect Circle\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"209\", \"artist\": \"Mad Season\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/32349839.jpg\", \"$area\": 209}, \"id\": \"album-Above\", \"name\": \"Above\"}], \"data\": {\"playcount\": 209, \"$area\": 209}, \"id\": \"artist_Mad Season\", \"name\": \"Mad Season\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"260\", \"artist\": \"Stone Temple Pilots\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/38753425.jpg\", \"$area\": 260}, \"id\": \"album-Tiny Music... Songs From the Vatican Gift Shop\", \"name\": \"Tiny Music... Songs From the Vatican Gift Shop\"}, {\"children\": [], \"data\": {\"playcount\": \"254\", \"artist\": \"Stone Temple Pilots\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B000002IU3.01.LZZZZZZZ.jpg\", \"$area\": 254}, \"id\": \"album-Core\", \"name\": \"Core\"}], \"data\": {\"playcount\": 514, \"$area\": 514}, \"id\": \"artist_Stone Temple Pilots\", \"name\": \"Stone Temple Pilots\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"181\", \"artist\": \"Bush\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8673371.jpg\", \"$area\": 181}, \"id\": \"album-The Science of Things\", \"name\": \"The Science of Things\"}], \"data\": {\"playcount\": 181, \"$area\": 181}, \"id\": \"artist_Bush\", \"name\": \"Bush\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"229\", \"artist\": \"Foo Fighters\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/32579429.jpg\", \"$area\": 229}, \"id\": \"album-Echoes, Silence, Patience & Grace\", \"name\": \"Echoes, Silence, Patience & Grace\"}, {\"children\": [], \"data\": {\"playcount\": \"185\", \"artist\": \"Foo Fighters\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B0009HLDFU.01.MZZZZZZZ.jpg\", \"$area\": 185}, \"id\": \"album-In Your Honor (disc 2)\", \"name\": \"In Your Honor (disc 2)\"}], \"data\": {\"playcount\": 414, \"$area\": 414}, \"id\": \"artist_Foo Fighters\", \"name\": \"Foo Fighters\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"398\", \"artist\": \"Luis Alberto Spinetta\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B00005LNP5.01._SCMZZZZZZZ_.jpg\", \"$area\": 398}, \"id\": \"album-Elija Y Gane\", \"name\": \"Elija Y Gane\"}, {\"children\": [], \"data\": {\"playcount\": \"203\", \"artist\": \"Luis Alberto Spinetta\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B0000B193V.01._SCMZZZZZZZ_.jpg\", \"$area\": 203}, \"id\": \"album-Para los Arboles\", \"name\": \"Para los Arboles\"}], \"data\": {\"playcount\": 601, \"$area\": 601}, \"id\": \"artist_Luis Alberto Spinetta\", \"name\": \"Luis Alberto Spinetta\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"224\", \"artist\": \"Alice in Chains\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/26497553.jpg\", \"$area\": 224}, \"id\": \"album-Music Bank\", \"name\": \"Music Bank\"}, {\"children\": [], \"data\": {\"playcount\": \"217\", \"artist\": \"Alice in Chains\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B0000296JW.01.MZZZZZZZ.jpg\", \"$area\": 217}, \"id\": \"album-Music Bank (disc 1)\", \"name\": \"Music Bank (disc 1)\"}, {\"children\": [], \"data\": {\"playcount\": \"215\", \"artist\": \"Alice in Chains\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B0000296JW.01.MZZZZZZZ.jpg\", \"$area\": 215}, \"id
|
||
|
//end
|
||
|
//init TreeMap
|
||
|
var tm = new $jit.TM.Squarified({
|
||
|
//where to inject the visualization
|
||
|
injectInto: 'infovis',
|
||
|
//show only one tree level
|
||
|
levelsToShow: 1,
|
||
|
//parent box title heights
|
||
|
titleHeight: 0,
|
||
|
//enable animations
|
||
|
animate: animate,
|
||
|
//box offsets
|
||
|
offset: 1,
|
||
|
//use canvas text
|
||
|
Label: {
|
||
|
type: labelType,
|
||
|
size: 9,
|
||
|
family: 'Tahoma, Verdana, Arial'
|
||
|
},
|
||
|
//enable specific canvas styles
|
||
|
//when rendering nodes
|
||
|
Node: {
|
||
|
CanvasStyles: {
|
||
|
shadowBlur: 0,
|
||
|
shadowColor: '#000'
|
||
|
}
|
||
|
},
|
||
|
//Attach left and right click events
|
||
|
Events: {
|
||
|
enable: true,
|
||
|
onClick: function(node) {
|
||
|
if(node) tm.enter(node);
|
||
|
},
|
||
|
onRightClick: function() {
|
||
|
tm.out();
|
||
|
},
|
||
|
//change node styles and canvas styles
|
||
|
//when hovering a node
|
||
|
onMouseEnter: function(node, eventInfo) {
|
||
|
if(node) {
|
||
|
//add node selected styles and replot node
|
||
|
node.setCanvasStyle('shadowBlur', 7);
|
||
|
node.setData('color', '#888');
|
||
|
tm.fx.plotNode(node, tm.canvas);
|
||
|
tm.labels.plotLabel(tm.canvas, node);
|
||
|
}
|
||
|
},
|
||
|
onMouseLeave: function(node) {
|
||
|
if(node) {
|
||
|
node.removeData('color');
|
||
|
node.removeCanvasStyle('shadowBlur');
|
||
|
tm.plot();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
//duration of the animations
|
||
|
duration: 1000,
|
||
|
//Enable tips
|
||
|
Tips: {
|
||
|
enable: true,
|
||
|
type: 'Native',
|
||
|
//add positioning offsets
|
||
|
offsetX: 20,
|
||
|
offsetY: 20,
|
||
|
//implement the onShow method to
|
||
|
//add content to the tooltip when a node
|
||
|
//is hovered
|
||
|
onShow: function(tip, node, isLeaf, domElement) {
|
||
|
var html = "<div class=\"tip-title\">" + node.name
|
||
|
+ "</div><div class=\"tip-text\">";
|
||
|
var data = node.data;
|
||
|
if(data.artist) {
|
||
|
html += "Artist: " + data.artist + "<br />";
|
||
|
}
|
||
|
if(data.playcount) {
|
||
|
html += "Play count: " + data.playcount;
|
||
|
}
|
||
|
if(data.image) {
|
||
|
html += "<img src=\""+ data.image +"\" class=\"album\" />";
|
||
|
}
|
||
|
tip.innerHTML = html;
|
||
|
}
|
||
|
},
|
||
|
//Implement this method for retrieving a requested
|
||
|
//subtree that has as root a node with id = nodeId,
|
||
|
//and level as depth. This method could also make a server-side
|
||
|
//call for the requested subtree. When completed, the onComplete
|
||
|
//callback method should be called.
|
||
|
request: function(nodeId, level, onComplete){
|
||
|
var tree = eval('(' + json + ')');
|
||
|
var subtree = $jit.json.getSubtree(tree, nodeId);
|
||
|
$jit.json.prune(subtree, 1);
|
||
|
onComplete.onComplete(nodeId, subtree);
|
||
|
},
|
||
|
//Add the name of the node in the corresponding label
|
||
|
//This method is called once, on label creation and only for DOM labels.
|
||
|
onCreateLabel: function(domElement, node){
|
||
|
domElement.innerHTML = node.name;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
var pjson = eval('(' + json + ')');
|
||
|
$jit.json.prune(pjson, 1);
|
||
|
|
||
|
tm.loadJSON(pjson);
|
||
|
tm.refresh();
|
||
|
//end
|
||
|
var sq = $jit.id('r-sq'),
|
||
|
st = $jit.id('r-st'),
|
||
|
sd = $jit.id('r-sd');
|
||
|
var util = $jit.util;
|
||
|
util.addEvent(sq, 'change', function() {
|
||
|
if(!sq.checked) return;
|
||
|
util.extend(tm, new $jit.Layouts.TM.Squarified);
|
||
|
tm.refresh();
|
||
|
});
|
||
|
util.addEvent(st, 'change', function() {
|
||
|
if(!st.checked) return;
|
||
|
util.extend(tm, new $jit.Layouts.TM.Strip);
|
||
|
tm.layout.orientation = "v";
|
||
|
tm.refresh();
|
||
|
});
|
||
|
util.addEvent(sd, 'change', function() {
|
||
|
if(!sd.checked) return;
|
||
|
util.extend(tm, new $jit.Layouts.TM.SliceAndDice);
|
||
|
tm.layout.orientation = "v";
|
||
|
tm.refresh();
|
||
|
});
|
||
|
//add event to the back button
|
||
|
var back = $jit.id('back');
|
||
|
$jit.util.addEvent(back, 'click', function() {
|
||
|
tm.out();
|
||
|
});
|
||
|
}
|