Skip to content

Commit

Permalink
fix icicle visualization (text clipping, direction)
Browse files Browse the repository at this point in the history
  • Loading branch information
davepacheco committed May 6, 2012
1 parent 8768eac commit 6eeaa15
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 55 deletions.
51 changes: 51 additions & 0 deletions lib/demo.js
@@ -0,0 +1,51 @@
/*
* demo.js: static-file node HTTP server for demos
*
* Usage: node demo.js [port]
*
* Sets up a web server on the given port (or port 80) serving static files
* out of the given path. This demo is NOT secure and allows anyone with
* network access to this server to read any files on your system.
*/

var mod_fs = require('fs');
var mod_http = require('http');
var mod_path = require('path');
var mod_url = require('url');

var dd_index = 'index.htm';
var dd_cwd = process.cwd();
var dd_port = 80;

var i;

for (i = 2; i < process.argv.length; i++) {
dd_port = parseInt(process.argv[i], 10);
if (isNaN(dd_port)) {
console.error('usage: node demo.js [port]');
process.exit(1);
}
}

mod_http.createServer(function (req, res) {
var uri = mod_url.parse(req.url).pathname;
var path;
var filename;

path = (uri == '/') ? dd_index : uri;

filename = mod_path.join(dd_cwd, path);

mod_fs.readFile(filename, function (err, file) {
if (err) {
res.writeHead(404);
res.end();
return;
}

res.writeHead(200);
res.end(file);
});
}).listen(dd_port, function () {
console.log('HTTP server started on port ' + dd_port);
});
2 changes: 1 addition & 1 deletion lib/www/icicle.htm
Expand Up @@ -9,7 +9,7 @@
</head>
<body>
<h1>Icicle Stack Visualization</h1>
<div id="chart"></div>
<div id="info">Hover over a block for details.</div>
<div id="chart"></div>
</body>
</html>
176 changes: 122 additions & 54 deletions lib/www/icicle.js
Expand Up @@ -2,81 +2,149 @@
* icicle.js: implements icicle visualization for stacks
*/

window.onload = svInit;
/* Configuration */
var svSvgWidth = 1000; /* image width */
var svSvgHeight = 650; /* image height */
var svGrowDown = false; /* if true, stacks are drawn growing down */
var svTransitionTime = 400; /* time for transition */
var svCornerPixels = 5; /* radius of rounded corners */
var svTextPaddingLeft = 5; /* padding-left on rectangle labels */
var svTextPaddingRight = 10; /* pading-right on rectangle labels */
var svTextPaddingTop = '1.2em'; /* padding-top on rectangle labels */

/* DOM nodes */
var svSvg; /* actual flame graph SVG object */
var svInfo; /* status box */

var svWidth = 1000;
var svHeight = 900;
var xScale, yScale, colorScale;
var svData, svRects, svText;
var svInfo;
/* d3 objects */
var svXScale; /* x-axis scale */
var svYScale; /* y-axis scale */
var svColorScale; /* color scale */
var svPartition; /* partition layout */
var svData; /* raw data, processed through layout */
var svRects; /* all rectangles (d3 selection) */
var svClips; /* clip paths (d3 selection) */
var svText; /* labels (d3 selection) */

/* d3 value functions */
var svId; /* clipping path node id */
var svColor; /* rectangle fill color */
var svHeight; /* height (rectangles and clip paths) */
var svRectWidth; /* rectangle width */
var svTextWidth; /* clip path width */
var svX; /* X-coordinate (rectangles and clip paths) */
var svY; /* Y-coordinate (rectangles and clip paths) */

window.onload = svInit;

function svInit()
{
xScale = d3.scale.linear().range([0, svWidth]);
yScale = d3.scale.linear().range([0, svHeight]);
colorScale = d3.scale.category20c();
svXScale = d3.scale.linear().range([0, svSvgWidth]);
svYScale = d3.scale.linear().range([0, svSvgHeight]);
svColorScale = d3.scale.category20c();

svInfo = d3.select('#info')[0][0].firstChild;

var vis = d3.select('#chart').append('svg:svg').
attr('width', svWidth).
attr('height', svHeight);
svSvg = d3.select('#chart').append('svg:svg')
.attr('width', svSvgWidth)
.attr('height', svSvgHeight);

var partition = d3.layout.partition().children(function (d) {
svPartition = d3.layout.partition().children(function (d) {
var rv = d3.entries(d.value.svChildren);
return (rv);
}).value(function (d) { return (d.value.svTotal); });
}).value(function (d) { return (d.value.svTotal); });

svId = function (d) {
return (d.data.key + '@' + svYScale(d.y) +
'@' + svXScale(d.x));
};
svColor = function (d) { return (svColorScale(d.data.key)); };
svHeight = function (d) { return (svYScale(d.dy)); };
svRectWidth = function (d) { return (svXScale(d.dx)); };
svTextWidth = function (d) {
return (Math.max(0, svRectWidth(d) - svTextPaddingRight));
};
svX = function (d) { return (svXScale(d.x)); };

if (svGrowDown)
svY = function (d) { return (svYScale(d.y)); };
else
svY = function (d) {
return (svSvgHeight - svYScale(d.y) - svHeight(d)); };

d3.json('sample.json', function (json) {
svData = partition(d3.entries(json)[0]);
svRects = vis.selectAll('rect').data(svData)
.enter().append('svg:rect')
.attr('x', function (d) { return (xScale(d.x)); })
.attr('y', function (d) { return (yScale(d.y)); })
.attr('rx', 5)
.attr('ry', 5)
.attr('width', function (d) { return (xScale(d.dx)); })
.attr('height', function (d) { return (yScale(d.dy)); })
.attr('fill', function (d) { return (colorScale(d.data.key)); })
.on('click', svClick)
.on('mouseover', svStatus);
svText = vis.selectAll('text').data(svData)
.enter().append('text')
.attr('x', function (d) { return (xScale(d.x)); })
.attr('y', function (d) { return (yScale(d.y)); })
.attr('dx', 5)
.attr('dy', '1.2em')
.attr('text-anchor', 'start')
.text(function (d) { return (d.data.key); });
svData = svPartition(d3.entries(json)[0]);

svRects = svSvg.selectAll('rect').data(svData)
.enter().append('svg:rect')
.attr('x', svX)
.attr('y', svY)
.attr('rx', svCornerPixels)
.attr('ry', svCornerPixels)
.attr('height', svHeight)
.attr('width', svRectWidth)
.attr('fill', svColor)
.on('click', svClick)
.on('mouseover', svStatus);

svClips = svSvg.selectAll('clipPath').data(svData)
.enter().append('svg:clipPath')
.attr('id', svId)
.append('svg:rect')
.attr('x', svX)
.attr('y', svY)
.attr('width', svTextWidth)
.attr('height', svHeight);

svText = svSvg.selectAll('text').data(svData)
.enter().append('text')
.attr('x', svX)
.attr('y', svY)
.attr('dx', svTextPaddingLeft)
.attr('dy', svTextPaddingTop)
.attr('clip-path', function (d) {
return ('url(#' + svId(d) + ')');
})
.text(function (d) { return (d.data.key); });
});
}

function svClick(cd)
{
xScale.domain([cd.x, cd.x + cd.dx]);
yScale.domain([cd.y, 1]).range([cd.y ? 20 : 0, svHeight]);
svXScale.domain([cd.x, cd.x + cd.dx]);
svYScale.domain([cd.y, 1]).range([cd.y ? 20 : 0, svSvgHeight]);

svHeight = function (d) {
return (svYScale(d.y + d.dy) - svYScale(d.y));
};

svRectWidth = function (d) {
return (svXScale(d.x + d.dx) - svXScale(d.x));
};

svTextWidth = function (d) {
return (Math.max(0, svXScale(d.x + d.dx) -
svXScale(d.x) - svTextPaddingRight));
};

svRects.transition()
.duration(400)
.attr('x', function (d) { return (xScale(d.x)); })
.attr('y', function (d) { return (yScale(d.y)); })
.attr('width', function (d) {
return (xScale(d.x + d.dx) - xScale(d.x));
})
.attr('height', function (d) {
return (yScale(d.y + d.dy) - yScale(d.y));
});
.duration(svTransitionTime)
.attr('x', svX)
.attr('y', svY)
.attr('width', svRectWidth)
.attr('height', svHeight);

svClips.transition()
.duration(svTransitionTime)
.attr('x', svX)
.attr('y', svY)
.attr('width', svTextWidth)
.attr('height', svHeight);

svText.transition()
.duration(400)
.attr('x', function (d) { return (xScale(d.x)); })
.attr('y', function (d) { return (yScale(d.y)); })
.attr('width', function (d) {
return (xScale(d.x + d.dx) - xScale(d.x));
})
.attr('height', function (d) {
return (yScale(d.y + d.dy) - yScale(d.y));
});
.duration(svTransitionTime)
.attr('x', svX)
.attr('y', svY);
}

function svStatus(d)
Expand Down

0 comments on commit 6eeaa15

Please sign in to comment.