Example of track with overlapping elements using TnT Board
Last active
May 23, 2016 08:39
-
-
Save emepyc/02931ac7797e1435d7b2fb035ba777f1 to your computer and use it in GitHub Desktop.
Non overlapping elements
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
tnt.board.track.feature.non_overlapping_block = function () { | |
var block_feature = tnt.board.track.feature.block(); | |
block_feature.create (function (blocks) { | |
var track = this; | |
var xScale = block_feature.scale(); | |
blocks | |
.append("rect") | |
.attr("x", function (d, i) { | |
return xScale(block_feature.from()(d, i)); | |
}) | |
.attr("y", function (d) { | |
var slots = block_feature.layout().slots(); | |
var height = track.height(); | |
pos = (height / slots) * d.slot; | |
return pos + 5; | |
}) | |
.attr("width", function (d, i) { | |
return (xScale(block_feature.to()(d, i)) - xScale(block_feature.from()(d, i))); | |
}) | |
.attr("height", function (d) { | |
var slots = block_feature.layout().slots(); | |
var height = track.height(); | |
return (height / slots) - 5; | |
}) | |
.attr("fill", track.color()) | |
.transition() | |
.duration(500) | |
.attr("fill", function (d) { | |
return block_feature.color()(d); | |
}); | |
}); | |
block_feature.distribute (function (blocks) { | |
var track = this; | |
var xScale = block_feature.scale(); | |
blocks | |
.select("rect") | |
.attr("width", function (d) { | |
return (xScale(d.end) - xScale(d.start)); | |
}) | |
.transition() | |
.duration(500) | |
.attr("y", function (d) { | |
var slots = block_feature.layout().slots(); | |
var height = track.height(); | |
pos = (height / slots) * d.slot; | |
return pos + 5; | |
}); | |
}); | |
return block_feature; | |
}; |
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
<!DOCTYPE html> | |
<head> | |
<link rel="stylesheet" href="https://tntvis.github.io/tnt.board/build/tnt.board.css" type="text/css" /> | |
<style> | |
#mydiv { | |
margin-top: 200px; | |
} | |
</style> | |
<script src="https://d3js.org/d3.v3.min.js"></script> | |
<!-- es6 promise only needed to "fake" async load of data --> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/3.2.2/es6-promise.min.js"></script> | |
<script src="http://tntvis.github.io/tnt.board/build/tnt.board.min.js"></script> | |
<script src="overlaps.js"></script> | |
<!-- New layout and new display that takes into account the vertical position of elements --> | |
<script src="layout.js"></script> | |
<script src="display.js"></script> | |
</head> | |
<body> | |
<div id="mydiv"></div> | |
<script> | |
var myBoard = tnt.board().from(20).to(500).max(500).width(950); | |
render (myBoard, document.getElementById("mydiv")); | |
</script> | |
</body> |
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
var layout = function () { | |
var needed_slots; | |
var scale; | |
var feature_height = 20; | |
var callback = function (){}; | |
var feature_layout = function (new_features) { | |
var track = this; | |
scale = track.display().scale(); | |
needed_slots = collition_detector(new_features); | |
track.height(needed_slots * feature_height); | |
callback(); | |
return new_features; | |
}; | |
function collition_detector (features) { | |
var allocated = []; | |
var remaining = features; | |
var needed_slots = 0; | |
for (var i=0; i<remaining.length; i++) { | |
var features_by_slot = sort_features_by_slot(allocated); | |
var current = remaining[i]; | |
var slot = 0; | |
OUTER: while (true) { | |
if (slot_has_space(current, features_by_slot[slot])) { | |
current.slot = slot; | |
allocated.push(current); | |
if (slot > needed_slots) { | |
needed_slots = slot; | |
} | |
break; | |
} | |
slot++; | |
} | |
} | |
return needed_slots + 1; | |
} | |
function slot_has_space (feature, features_in_slot) { | |
if (!features_in_slot) { | |
return true; | |
} | |
for (var i=0; i<features_in_slot.length; i++) { | |
var subject = features_in_slot[i]; | |
var y1 = scale(subject.start); | |
var y2 = scale(subject.end); | |
var x1 = scale(feature.start); | |
var x2 = scale(feature.end); | |
if ( ((x1 <= y1) && (x2 >= y1)) || | |
((x1 >= y1) && (x1 <= y2)) ) { | |
return false; | |
} | |
} | |
return true; | |
} | |
function sort_features_by_slot (features) { | |
var slots = []; | |
for (var i=0; i<features.length; i++) { | |
var feature = features[i]; | |
if (!slots[feature.slot]) { | |
slots[feature.slot] = []; | |
} | |
slots[feature.slot].push(feature); | |
} | |
return slots; | |
} | |
feature_layout.elements = function () {}; | |
feature_layout.slots = function () { | |
return needed_slots; | |
}; | |
feature_layout.on_run = function(cbak) { | |
callback = cbak; | |
return this; | |
}; | |
return feature_layout; | |
}; |
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
// Change the data and the algorithm will detect the overlapping elements | |
var data = [ | |
{start:10, end:50, id:1, val:0.3}, | |
{start:30, end:40, id:2, val:0.9}, | |
{start:50, end:60, id:3, val:1.0}, | |
{start:70, end:80, id:4, val:0.1}, | |
{start:35, end:80, id:5, val:0.4}, | |
{start:65, end:80, id:6, val:0.7}, | |
{start:75, end:90, id:7, val:0.1}, | |
{start:90, end:95, id:8, val:0.8}, | |
{start:5, end:15, id:9, val:0.6}, | |
{start:10, end:50, id:10, val:0.5} | |
]; | |
function render (board, div) { | |
var current_height = 200; | |
// The color gradient | |
var col_grad = d3.scale.linear() | |
.domain([0,1]) | |
.range(["#eff3ff","#08519c"]); | |
var axis_track = tnt.board.track() | |
.height(0) | |
.color("white") | |
.display(tnt.board.track.feature.axis() | |
.orientation("top") | |
); | |
var feature_track = tnt.board.track() | |
.height(50) | |
.color('white') | |
// The new defined block with no overlaps | |
.display(tnt.board.track.feature.non_overlapping_block() | |
.color(function (d) { | |
return col_grad(d.val); | |
}) | |
.index(function (d) { | |
return d.id; | |
}) | |
) | |
.data(tnt.board.track.data.sync() | |
.retriever(function (where) { | |
return filterData(data, where.from, where.to); | |
}) | |
); | |
feature_track | |
.display(feature_track.display() | |
.layout(layout() | |
.on_run(function () { | |
board.tracks(board.tracks()); | |
})) | |
); | |
function filterData (recs, from, to) { | |
var filtered = []; | |
for (var i=0; i<recs.length; i++) { | |
var data = recs[i]; | |
if (((data.start >= from) && (data.start <= to)) || | |
((data.end >= from) && (data.end <= to)) || | |
((data.start <= from) && (data.end >= to)) || | |
((data.start >= from) && (data.end <= to))) { | |
filtered.push(data); | |
} | |
} | |
return filtered; | |
} | |
board.from(0).to(100).max(120).min(0).zoom_out(120).zoom_in(20); | |
board.add_track([axis_track, feature_track]); | |
board(div); | |
board.start(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment