use strict;
use warnings;
+use DBI;
+use DBD::SQLite;
+
use Getopt::Long;
GetOptions(
'json!' => \my $opt_json,
+ 'db=s' => \my $opt_db,
) or exit 1;
+my $dbh = DBI->connect("dbi:SQLite:dbname=$opt_db","","", {
+ RaiseError => 1, PrintError => 0, AutoCommit => 0
+});
+$dbh->do("PRAGMA synchronous = OFF");
+$dbh->do("DROP TABLE IF EXISTS node");
+$dbh->do(q{
+ CREATE TABLE node (
+ id integer primary key,
+ name text,
+ depth integer,
+ parent_seqn integer,
+
+ self_size integer,
+ kids_size integer,
+ kids_node_count integer,
+ child_seqns text
+ )
+});
+my $node_ins_sth = $dbh->prepare(q{
+ INSERT INTO node VALUES (?,?,?,?, ?,?,?,?)
+});
+
my @stack;
my %seqn2node;
my $x = shift;
if ($opt_json) {
print " " x $x->{depth};
- print qq({ "id": "$x->{seqn}", "name": "$x->{name}", "depth":$x->{depth}, "children":[ \n);
+ print qq({ "id": "$x->{id}", "name": "$x->{name}", "depth":$x->{depth}, "children":[ \n);
}
return;
}
sub leave_node {
my $x = shift;
- delete $seqn2node{$x->{seqn}};
+ delete $seqn2node{$x->{id}};
my $self_size = 0; $self_size += $_ for values %{$x->{leaves}};
$x->{self_size} = $self_size;
if (my $parent = $stack[-1]) {
# link to parent
- $x->{parent_seqn} = $parent->{seqn};
+ $x->{parent_seqn} = $parent->{id};
# accumulate into parent
$parent->{kids_node_count} += 1 + ($x->{kids_node_count}||0);
$parent->{kids_size} += $self_size + $x->{kids_size};
- push @{$parent->{child_seqn}}, $x->{seqn};
+ push @{$parent->{child_seqn}}, $x->{id};
}
# output
# ...
my $size = $self_size + $x->{kids_size};
print qq(], "data":{ "\$area": $size } },\n);
}
+ if ($dbh) {
+ $node_ins_sth->execute(
+ $x->{id}, $x->{name}, $x->{depth}, $x->{parent_seqn},
+ $x->{self_size}, $x->{kids_size}, $x->{kids_node_count},
+ $x->{child_seqn} ? join(",", @{$x->{child_seqn}}) : undef
+ );
+ # XXX attribs
+ }
return;
}
while (<>) {
chomp;
- my ($type, $seqn, $val, $name, $extra) = split / /, $_, 5;
+ my ($type, $id, $val, $name, $extra) = split / /, $_, 5;
if ($type eq "N") { # Node ($val is depth)
while ($val < @stack) {
leave_node(my $x = pop @stack);
- warn "N $seqn d$val ends $x->{seqn} d$x->{depth}: size $x->{self_size}+$x->{kids_size}\n";
+ warn "N $id d$val ends $x->{id} d$x->{depth}: size $x->{self_size}+$x->{kids_size}\n";
}
die 1 if $stack[$val];
- my $node = $stack[$val] = { seqn => $seqn, name => $name, extra => $extra, attr => [], leaves => {}, depth => $val, self_size=>0, kids_size=>0 };
+ my $node = $stack[$val] = { id => $id, name => $name, extra => $extra, attr => [], leaves => {}, depth => $val, self_size=>0, kids_size=>0 };
enter_node($node);
- $seqn2node{$seqn} = $node;
+ $seqn2node{$id} = $node;
}
elsif ($type eq "L") { # Leaf name and memory size
- my $node = $seqn2node{$seqn} || die;
+ my $node = $seqn2node{$id} || die;
$node->{leaves}{$name} += $val;
}
elsif ($type eq "A") { # Attribute name and value
- my $node = $seqn2node{$seqn} || die;
+ my $node = $seqn2node{$id} || die;
push @{ $node->{attr} }, $name, $val; # pairs
}
else {
warn "Invalid type '$type' on line $. ($_)";
}
+ $dbh->commit if $dbh and $id % 10_000 == 0;
}
my $x;
while (@stack > 1) {
leave_node($x = pop @stack) while @stack;
- warn "EOF ends $x->{seqn} d$x->{depth}: size $x->{self_size}+$x->{kids_size}\n";
+ warn "EOF ends $x->{id} d$x->{depth}: size $x->{self_size}+$x->{kids_size}\n";
}
print " ];\n" if $opt_json;
+$dbh->commit if $dbh;
+
use Data::Dumper;
warn Dumper(\$x);
warn Dumper(\%seqn2node);
--- /dev/null
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Mojolicious::Lite;
+
+use ORLite {
+ file => '../x.db',
+ package => "MemView",
+ #user_version => 1,
+ readonly => 1,
+ #unicode => 1,
+};
+
+# Documentation browser under "/perldoc"
+plugin 'PODRenderer';
+
+get '/' => sub {
+ my $self = shift;
+ $self->render('index');
+};
+
+get '/jit_tree/:id/:depth' => sub {
+ my $self = shift;
+ my $id = $self->stash('id');
+ my $depth = $self->stash('depth');
+ warn "jit_tree $id $depth";
+ my $jit_tree = _fetch_node($id, $depth, sub {
+ my $node=shift; $node->{data}{'$area'} = $node->{self_size}+$node->{kids_size}
+ });
+ use Devel::Dwarn; Dwarn($jit_tree);
+ $self->render_json($jit_tree);
+};
+
+sub _fetch_node {
+ my ($id, $depth, $transform) = @_;
+ my $node = MemView->selectrow_hashref("select * from node where id = ?", undef, $id);
+ if ($depth && $node->{child_seqns}) {
+ my @child_seqns = split /,/, $node->{child_seqns};
+ my @children = map { _fetch_node($_, $depth-1, $transform) } @child_seqns;
+ $node->{children} = \@children;
+ }
+ $transform->($node) if $transform;
+ return $node;
+}
+
+
+app->start;
+__DATA__
+@@ index.html.ep
+% layout 'default';
+% title 'Welcome';
+Welcome to the Mojolicious real-time web framework!
+
+@@ layouts/default.html.ep
+<!DOCTYPE html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>Treemap - TreeMap with on-demand nodes</title>
+
+<!-- CSS Files -->
+<link type="text/css" href="css/base.css" rel="stylesheet" />
+<link type="text/css" href="css/Treemap.css" rel="stylesheet" />
+
+<!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
+
+<!-- JIT Library File -->
+<script language="javascript" type="text/javascript" src="jit.js"></script>
+<script language="javascript" type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
+
+<!-- Example File -->
+<script language="javascript" type="text/javascript" src="tmdata.js"></script>
+<script language="javascript" type="text/javascript" src="tm.js"></script>
+</head>
+
+<body onload="init();">
+<div id="container">
+
+<div id="left-container">
+
+
+
+<div class="text">
+<h4>
+TreeMap with on-demand nodes
+</h4>
+
+ This example shows how you can use the <b>request</b> controller method to create a TreeMap with on demand nodes<br /><br />
+ This example makes use of native Canvas text and shadows, but can be easily adapted to use HTML like the other examples.<br /><br />
+ There should be only one level shown at a time.<br /><br />
+ Clicking on a band should show a new TreeMap with its most listened albums.<br /><br />
+
+</div>
+
+<div id="id-list">
+<table>
+ <tr>
+ <td>
+ <label for="r-sq">Squarified </label>
+ </td>
+ <td>
+ <input type="radio" id="r-sq" name="layout" checked="checked" value="left" />
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label for="r-st">Strip </label>
+ </td>
+ <td>
+ <input type="radio" id="r-st" name="layout" value="top" />
+ </td>
+ <tr>
+ <td>
+ <label for="r-sd">SliceAndDice </label>
+ </td>
+ <td>
+ <input type="radio" id="r-sd" name="layout" value="bottom" />
+ </td>
+ </tr>
+</table>
+</div>
+
+<a id="back" href="#" class="theme button white">Go to Parent</a>
+
+
+<div style="text-align:center;"><a href="example2.js">See the Example Code</a></div>
+</div>
+
+<div id="center-container">
+ <div id="infovis"></div>
+</div>
+
+<div id="right-container">
+
+<div id="inner-details"></div>
+
+</div>
+
+<div id="log"></div>
+</div>
+</body>
+</html>
--- /dev/null
+html, body {
+ margin:0;
+ padding:0;
+ font-family: "Lucida Grande", Verdana;
+ font-size: 0.9em;
+ text-align: center;
+ background-color:#F2F2F2;
+}
+
+input, select {
+ font-size:0.9em;
+}
+
+table {
+ margin-top:-10px;
+ margin-left:7px;
+}
+
+h4 {
+ font-size:1.1em;
+ text-decoration:none;
+ font-weight:normal;
+ color:#23A4FF;
+}
+
+a {
+ color:#23A4FF;
+}
+
+#container {
+ width: 1000px;
+ height: 600px;
+ margin:0 auto;
+ position:relative;
+}
+
+#left-container,
+#right-container,
+#center-container {
+ height:600px;
+ position:absolute;
+ top:0;
+}
+
+#left-container, #right-container {
+ width:200px;
+ color:#686c70;
+ text-align: left;
+ overflow: auto;
+ background-color:#fff;
+ background-repeat:no-repeat;
+ border-bottom:1px solid #ddd;
+}
+
+#left-container {
+ left:0;
+ background-image:url('col2.png');
+ background-position:center right;
+ border-left:1px solid #ddd;
+
+}
+
+#right-container {
+ right:0;
+ background-image:url('col1.png');
+ background-position:center left;
+ border-right:1px solid #ddd;
+}
+
+#right-container h4{
+ text-indent:8px;
+}
+
+#center-container {
+ width:600px;
+ left:200px;
+ background-color:#1a1a1a;
+ color:#ccc;
+}
+
+.text {
+ margin: 7px;
+}
+
+#inner-details {
+ font-size:0.8em;
+ list-style:none;
+ margin:7px;
+}
+
+#log {
+ position:absolute;
+ top:10px;
+ font-size:1.0em;
+ font-weight:bold;
+ color:#23A4FF;
+}
+
+
+#infovis {
+ position:relative;
+ width:600px;
+ height:600px;
+ margin:auto;
+ overflow:hidden;
+}
+
+/*TOOLTIPS*/
+.tip {
+ color: #111;
+ width: 139px;
+ background-color: white;
+ border:1px solid #ccc;
+ -moz-box-shadow:#555 2px 2px 8px;
+ -webkit-box-shadow:#555 2px 2px 8px;
+ -o-box-shadow:#555 2px 2px 8px;
+ box-shadow:#555 2px 2px 8px;
+ opacity:0.9;
+ filter:alpha(opacity=90);
+ font-size:10px;
+ font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
+ padding:7px;
+}
\ No newline at end of file
--- /dev/null
+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
+ //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){
+ if (true) {
+ jQuery.getJSON('jit_tree/'+nodeId+'/3', function(data) {
+ onComplete.onComplete(nodeId, data);
+ });
+ }
+ else {
+ var tree = memnodes[0];
+ var subtree = $jit.json.getSubtree(tree, nodeId);
+ $jit.json.prune(subtree, 2);
+ 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;
+ }
+ });
+
+if(true) {
+ jQuery.getJSON('jit_tree/1/2', function(data) {
+ console.log(data);
+ tm.loadJSON(data);
+ tm.refresh();
+ });
+}
+else {
+ //var pjson = eval('(' + json + ')');
+ var pjson = memnodes[0];
+ $jit.json.prune(pjson, 2);
+ console.log(pjson);
+ tm.loadJSON(pjson);
+ tm.refresh();
+}
+
+ 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();
+ });
+}
+++ /dev/null
-<!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>Treemap - TreeMap with on-demand nodes</title>
-
-<!-- CSS Files -->
-<link type="text/css" href="css/base.css" rel="stylesheet" />
-<link type="text/css" href="css/Treemap.css" rel="stylesheet" />
-
-<!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
-
-<!-- JIT Library File -->
-<script language="javascript" type="text/javascript" src="jit.js"></script>
-
-<!-- Example File -->
-<script language="javascript" type="text/javascript" src="tmdata.js"></script>
-<script language="javascript" type="text/javascript" src="tm.js"></script>
-</head>
-
-<body onload="init();">
-<div id="container">
-
-<div id="left-container">
-
-
-
-<div class="text">
-<h4>
-TreeMap with on-demand nodes
-</h4>
-
- This example shows how you can use the <b>request</b> controller method to create a TreeMap with on demand nodes<br /><br />
- This example makes use of native Canvas text and shadows, but can be easily adapted to use HTML like the other examples.<br /><br />
- There should be only one level shown at a time.<br /><br />
- Clicking on a band should show a new TreeMap with its most listened albums.<br /><br />
-
-</div>
-
-<div id="id-list">
-<table>
- <tr>
- <td>
- <label for="r-sq">Squarified </label>
- </td>
- <td>
- <input type="radio" id="r-sq" name="layout" checked="checked" value="left" />
- </td>
- </tr>
- <tr>
- <td>
- <label for="r-st">Strip </label>
- </td>
- <td>
- <input type="radio" id="r-st" name="layout" value="top" />
- </td>
- <tr>
- <td>
- <label for="r-sd">SliceAndDice </label>
- </td>
- <td>
- <input type="radio" id="r-sd" name="layout" value="bottom" />
- </td>
- </tr>
-</table>
-</div>
-
-<a id="back" href="#" class="theme button white">Go to Parent</a>
-
-
-<div style="text-align:center;"><a href="example2.js">See the Example Code</a></div>
-</div>
-
-<div id="center-container">
- <div id="infovis"></div>
-</div>
-
-<div id="right-container">
-
-<div id="inner-details"></div>
-
-</div>
-
-<div id="log"></div>
-</div>
-</body>
-</html>
+++ /dev/null
-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\": \"album-Music Bank (disc 2)\", \"name\": \"Music Bank (disc 2)\"}, {\"children\": [], \"data\": {\"playcount\": \"181\", \"artist\": \"Alice in Chains\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B0000296JW.01.MZZZZZZZ.jpg\", \"$area\": 181}, \"id\": \"album-Music Bank (disc 3)\", \"name\": \"Music Bank (disc 3)\"}], \"data\": {\"playcount\": 837, \"$area\": 837}, \"id\": \"artist_Alice in Chains\", \"name\": \"Alice in Chains\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"627\", \"artist\": \"Tool\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8480501.jpg\", \"$area\": 627}, \"id\": \"album-10,000 Days\", \"name\": \"10,000 Days\"}], \"data\": {\"playcount\": 627, \"$area\": 627}, \"id\": \"artist_Tool\", \"name\": \"Tool\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"261\", \"artist\": \"Chris Cornell\", \"image\": \"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png\", \"$area\": 261}, \"id\": \"album-2006-09-07: O-Bar, Stockholm, Sweden\", \"name\": \"2006-09-07: O-Bar, Stockholm, Sweden\"}, {\"children\": [], \"data\": {\"playcount\": \"211\", \"artist\": \"Chris Cornell\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/25402479.jpg\", \"$area\": 211}, \"id\": \"album-Lost and Found\", \"name\": \"Lost and Found\"}], \"data\": {\"playcount\": 472, \"$area\": 472}, \"id\": \"artist_Chris Cornell\", \"name\": \"Chris Cornell\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"197\", \"artist\": \"Disturbed\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8634627.jpg\", \"$area\": 197}, \"id\": \"album-The Sickness\", \"name\": \"The Sickness\"}], \"data\": {\"playcount\": 197, \"$area\": 197}, \"id\": \"artist_Disturbed\", \"name\": \"Disturbed\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"493\", \"artist\": \"Erykah Badu\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8591345.jpg\", \"$area\": 493}, \"id\": \"album-Mama's Gun\", \"name\": \"Mama's Gun\"}], \"data\": {\"playcount\": 493, \"$area\": 493}, \"id\": \"artist_Erykah Badu\", \"name\": \"Erykah Badu\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"249\", \"artist\": \"Audioslave\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/32070871.jpg\", \"$area\": 249}, \"id\": \"album-Audioslave\", \"name\": \"Audioslave\"}], \"data\": {\"playcount\": 249, \"$area\": 249}, \"id\": \"artist_Audioslave\", \"name\": \"Audioslave\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"359\", \"artist\": \"Soda Stereo\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/15858421.jpg\", \"$area\": 359}, \"id\": \"album-Comfort y M\u00fasica Para Volar\", \"name\": \"Comfort y M\u00fasica Para Volar\"}], \"data\": {\"playcount\": 359, \"$area\": 359}, \"id\": \"artist_Soda Stereo\", \"name\": \"Soda Stereo\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"302\", \"artist\": \"Sinch\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8776205.jpg\", \"$area\": 302}, \"id\": \"album-Clearing the Channel\", \"name\": \"Clearing the Channel\"}], \"data\": {\"playcount\": 302, \"$area\": 302}, \"id\": \"artist_Sinch\", \"name\": \"Sinch\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"177\", \"artist\": \"Dave Matthews Band\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/32457599.jpg\", \"$area\": 177}, \"id\": \"album-Crash\", \"name\": \"Crash\"}], \"data\": {\"playcount\": 177, \"$area\": 177}, \"id\": \"artist_Dave Matthews Band\", \"name\": \"Dave Matthews Band\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"207\", \"artist\": \"Pearl Jam\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/30352203.jpg\", \"$area\": 207}, \"id\": \"album-Vs.\", \"name\": \"Vs.\"}], \"data\": {\"playcount\": 207, \"$area\": 207}, \"id\": \"artist_Pearl Jam\", \"name\": \"Pearl Jam\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"486\", \"artist\": \"Kr\u00f8m\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/26053425.jpg\", \"$area\": 486}, \"id\": \"album-It All Makes Sense Now\", \"name\": \"It All Makes Sense Now\"}, {\"children\": [], \"data\": {\"playcount\": \"251\", \"artist\": \"Agua de Annique\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/9658733.jpg\", \"$area\": 251}, \"id\": \"album-Air\", \"name\": \"Air\"}], \"data\": {\"playcount\": 737, \"$area\": 737}, \"id\": \"artist_Kr\u00f8m\", \"name\": \"Kr\u00f8m\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"345\", \"artist\": \"Temple of the Dog\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8605651.jpg\", \"$area\": 345}, \"id\": \"album-Temple Of The Dog\", \"name\": \"Temple Of The Dog\"}], \"data\": {\"playcount\": 345, \"$area\": 345}, \"id\": \"artist_Temple of the Dog\", \"name\": \"Temple of the Dog\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"318\", \"artist\": \"Nine Inch Nails\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/29274729.jpg\", \"$area\": 318}, \"id\": \"album-And All That Could Have Been (Still)\", \"name\": \"And All That Could Have Been (Still)\"}], \"data\": {\"playcount\": 318, \"$area\": 318}, \"id\": \"artist_Nine Inch Nails\", \"name\": \"Nine Inch Nails\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"256\", \"artist\": \"Tryo\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/32595059.jpg\", \"$area\": 256}, \"id\": \"album-Mamagubida\", \"name\": \"Mamagubida\"}, {\"children\": [], \"data\": {\"playcount\": \"220\", \"artist\": \"Tryo\", \"image\": \"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png\", \"$area\": 220}, \"id\": \"album-Reggae \u00e0 Coup de Cirque\", \"name\": \"Reggae \u00e0 Coup de Cirque\"}, {\"children\": [], \"data\": {\"playcount\": \"181\", \"artist\": \"Tryo\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/16799743.jpg\", \"$area\": 181}, \"id\": \"album-Grain de sable\", \"name\": \"Grain de sable\"}], \"data\": {\"playcount\": 657, \"$area\": 657}, \"id\": \"artist_Tryo\", \"name\": \"Tryo\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"258\", \"artist\": \"Sublime\", \"image\": \"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png\", \"$area\": 258}, \"id\": \"album-Best Of\", \"name\": \"Best Of\"}, {\"children\": [], \"data\": {\"playcount\": \"176\", \"artist\": \"Sublime\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/5264426.jpg\", \"$area\": 176}, \"id\": \"album-Robbin' The Hood\", \"name\": \"Robbin' The Hood\"}], \"data\": {\"playcount\": 434, \"$area\": 434}, \"id\": \"artist_Sublime\", \"name\": \"Sublime\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"418\", \"artist\": \"Red Hot Chili Peppers\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8590493.jpg\", \"$area\": 418}, \"id\": \"album-One Hot Minute\", \"name\": \"One Hot Minute\"}], \"data\": {\"playcount\": 418, \"$area\": 418}, \"id\": \"artist_Red Hot Chili Peppers\", \"name\": \"Red Hot Chili Peppers\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"275\", \"artist\": \"Guns N' Roses\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/17597653.jpg\", \"$area\": 275}, \"id\": \"album-Chinese Democracy\", \"name\": \"Chinese Democracy\"}, {\"children\": [], \"data\": {\"playcount\": \"203\", \"artist\": \"Guns N' Roses\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/15231979.jpg\", \"$area\": 203}, \"id\": \"album-Use Your Illusion II\", \"name\": \"Use Your Illusion II\"}], \"data\": {\"playcount\": 478, \"$area\": 478}, \"id\": \"artist_Guns N' Roses\", \"name\": \"Guns N' Roses\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"208\", \"artist\": \"Wax Tailor\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B0007LCNNE.01.MZZZZZZZ.jpg\", \"$area\": 208}, \"id\": \"album-Tales of the Forgotten Melodies\", \"name\": \"Tales of the Forgotten Melodies\"}], \"data\": {\"playcount\": 208, \"$area\": 208}, \"id\": \"artist_Wax Tailor\", \"name\": \"Wax Tailor\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"208\", \"artist\": \"Radiohead\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/7862623.png\", \"$area\": 208}, \"id\": \"album-In Rainbows\", \"name\": \"In Rainbows\"}], \"data\": {\"playcount\": 208, \"$area\": 208}, \"id\": \"artist_Radiohead\", \"name\": \"Radiohead\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"317\", \"artist\": \"Soundgarden\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8600371.jpg\", \"$area\": 317}, \"id\": \"album-Down On The Upside\", \"name\": \"Down On The Upside\"}, {\"children\": [], \"data\": {\"playcount\": \"290\", \"artist\": \"Soundgarden\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8590515.jpg\", \"$area\": 290}, \"id\": \"album-Superunknown\", \"name\": \"Superunknown\"}], \"data\": {\"playcount\": 607, \"$area\": 607}, \"id\": \"artist_Soundgarden\", \"name\": \"Soundgarden\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"247\", \"artist\": \"Blind Melon\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/15113951.jpg\", \"$area\": 247}, \"id\": \"album-Nico\", \"name\": \"Nico\"}, {\"children\": [], \"data\": {\"playcount\": \"218\", \"artist\": \"Blind Melon\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/45729417.jpg\", \"$area\": 218}, \"id\": \"album-Soup\", \"name\": \"Soup\"}, {\"children\": [], \"data\": {\"playcount\": \"197\", \"artist\": \"Blind Melon\", \"image\": \"http:\/\/images.amazon.com\/images\/P\/B00005V5PW.01.MZZZZZZZ.jpg\", \"$area\": 197}, \"id\": \"album-Classic Masters\", \"name\": \"Classic Masters\"}, {\"children\": [], \"data\": {\"playcount\": \"194\", \"artist\": \"Blind Melon\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/15157989.jpg\", \"$area\": 194}, \"id\": \"album-Blind Melon\", \"name\": \"Blind Melon\"}], \"data\": {\"playcount\": 856, \"$area\": 856}, \"id\": \"artist_Blind Melon\", \"name\": \"Blind Melon\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"537\", \"artist\": \"Incubus\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/17594883.jpg\", \"$area\": 537}, \"id\": \"album-Make Yourself\", \"name\": \"Make Yourself\"}, {\"children\": [], \"data\": {\"playcount\": \"258\", \"artist\": \"Incubus\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/31550385.jpg\", \"$area\": 258}, \"id\": \"album-Light Grenades\", \"name\": \"Light Grenades\"}, {\"children\": [], \"data\": {\"playcount\": \"181\", \"artist\": \"Incubus\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/32309285.jpg\", \"$area\": 181}, \"id\": \"album-Morning View\", \"name\": \"Morning View\"}], \"data\": {\"playcount\": 976, \"$area\": 976}, \"id\": \"artist_Incubus\", \"name\": \"Incubus\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"198\", \"artist\": \"Jack Johnson\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/8599099.jpg\", \"$area\": 198}, \"id\": \"album-On And On\", \"name\": \"On And On\"}, {\"children\": [], \"data\": {\"playcount\": \"186\", \"artist\": \"Jack Johnson\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/30082075.jpg\", \"$area\": 186}, \"id\": \"album-Brushfire Fairytales\", \"name\": \"Brushfire Fairytales\"}], \"data\": {\"playcount\": 384, \"$area\": 384}, \"id\": \"artist_Jack Johnson\", \"name\": \"Jack Johnson\"}, {\"children\": [{\"children\": [], \"data\": {\"playcount\": \"349\", \"artist\": \"Mother Love Bone\", \"image\": \"http:\/\/userserve-ak.last.fm\/serve\/300x300\/21881921.jpg\", \"$area\": 349}, \"id\": \"album-Mother Love Bone\", \"name\": \"Mother Love Bone\"}], \"data\": {\"playcount\": 349, \"$area\": 349}, \"id\": \"artist_Mother Love Bone\", \"name\": \"Mother Love Bone\"}], \"data\": {}, \"id\": \"root\", \"name\": \"Top Albums\"}";
- //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 tree = memnodes[0];
- var subtree = $jit.json.getSubtree(tree, nodeId);
- $jit.json.prune(subtree, 2);
- 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 + ')');
- var pjson = memnodes[0];
- $jit.json.prune(pjson, 2);
-
- 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();
- });
-}
+++ /dev/null
-<!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>Treemap - TreeMap with on-demand nodes</title>
-
-<!-- CSS Files -->
-<link type="text/css" href="css/base.css" rel="stylesheet" />
-<link type="text/css" href="css/Treemap.css" rel="stylesheet" />
-
-<!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
-
-<!-- JIT Library File -->
-<script language="javascript" type="text/javascript" src="jit.js"></script>
-
-<!-- Example File -->
-<script language="javascript" type="text/javascript" src="tm0data.js"></script>
-<script language="javascript" type="text/javascript" src="tm0.js"></script>
-</head>
-
-<body onload="init();">
-<div id="container">
-
-<div id="left-container">
-
-
-
-<div class="text">
-<h4>
-TreeMap with on-demand nodes
-</h4>
-
- This example shows how you can use the <b>request</b> controller method to create a TreeMap with on demand nodes<br /><br />
- This example makes use of native Canvas text and shadows, but can be easily adapted to use HTML like the other examples.<br /><br />
- There should be only one level shown at a time.<br /><br />
- Clicking on a band should show a new TreeMap with its most listened albums.<br /><br />
-
-</div>
-
-<div id="id-list">
-<table>
- <tr>
- <td>
- <label for="r-sq">Squarified </label>
- </td>
- <td>
- <input type="radio" id="r-sq" name="layout" checked="checked" value="left" />
- </td>
- </tr>
- <tr>
- <td>
- <label for="r-st">Strip </label>
- </td>
- <td>
- <input type="radio" id="r-st" name="layout" value="top" />
- </td>
- <tr>
- <td>
- <label for="r-sd">SliceAndDice </label>
- </td>
- <td>
- <input type="radio" id="r-sd" name="layout" value="bottom" />
- </td>
- </tr>
-</table>
-</div>
-
-<a id="back" href="#" class="theme button white">Go to Parent</a>
-
-
-<div style="text-align:center;"><a href="example2.js">See the Example Code</a></div>
-</div>
-
-<div id="center-container">
- <div id="infovis"></div>
-</div>
-
-<div id="right-container">
-
-<div id="inner-details"></div>
-
-</div>
-
-<div id="log"></div>
-</div>
-</body>
-</html>