Simon Hunt

Added basic drag and select behavior to nodes.

Changed base colors and added .pkt and .opt classes to differentiate nodes.
......@@ -32,20 +32,20 @@
<div id="view"></div>
</div>
// Initialize the UI...
<!-- Initialize the UI...-->
<script type="text/javascript">
var ONOS = $.onos({note: "config, if needed"});
</script>
// include module files
// + mast.js
// + nav.js
// + .... application views
<!-- include module files-->
<!-- + mast.js-->
<!-- + nav.js-->
<!-- + .... application views-->
// for now, we are just bootstrapping the network visualization
<!-- for now, we are just bootstrapping the network visualization-->
<script src="network.js" type="text/javascript"></script>
// finally, build the UI
<!-- finally, build the UI-->
<script type="text/javascript">
$(ONOS.buildUi);
</script>
......
......@@ -100,7 +100,7 @@
network.data.nodes.forEach(function(n) {
var ypc = yPosConstraintForNode(n),
ix = Math.random() * 0.8 * nw + 0.1 * nw,
ix = Math.random() * 0.6 * nw + 0.2 * nw,
iy = ypc * nh,
node = {
id: n.id,
......@@ -152,11 +152,49 @@
.attr('width', view.width)
.attr('height', view.height)
.append('g')
.attr('transform', config.force.translate());
// .attr('id', 'zoomable')
.attr('transform', config.force.translate())
// .call(d3.behavior.zoom().on("zoom", zoomRedraw));
// function zoomRedraw() {
// d3.select("#zoomable").attr("transform",
// "translate(" + d3.event.translate + ")"
// + " scale(" + d3.event.scale + ")");
// }
// TODO: svg.append('defs') for markers?
// TODO: move glow/blur stuff to util script
var glow = network.svg.append('filter')
.attr('x', '-50%')
.attr('y', '-50%')
.attr('width', '200%')
.attr('height', '200%')
.attr('id', 'blue-glow');
glow.append('feColorMatrix')
.attr('type', 'matrix')
.attr('values', '0 0 0 0 0 ' +
'0 0 0 0 0 ' +
'0 0 0 0 .7 ' +
'0 0 0 1 0 ');
glow.append('feGaussianBlur')
.attr('stdDeviation', 3)
.attr('result', 'coloredBlur');
glow.append('feMerge').selectAll('feMergeNode')
.data(['coloredBlur', 'SourceGraphic'])
.enter().append('feMergeNode')
.attr('in', String);
// TODO: svg.append('defs')
// TODO: glow/blur stuff
// TODO: legend (and auto adjust on scroll)
// $('#view').on('scroll', function() {
//
// });
network.link = network.svg.append('g').selectAll('.link')
.data(network.force.links(), function(d) {return d.id})
......@@ -164,27 +202,90 @@
.attr('class', 'link');
// TODO: drag behavior
// TODO: closest node deselect
network.draggedThreshold = d3.scale.linear()
.domain([0, 0.1])
.range([5, 20])
.clamp(true);
function dragged(d) {
var threshold = network.draggedThreshold(network.force.alpha()),
dx = d.oldX - d.px,
dy = d.oldY - d.py;
if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
d.dragged = true;
}
return d.dragged;
}
network.drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on('dragstart', function(d) {
d.oldX = d.x;
d.oldY = d.y;
d.dragged = false;
d.fixed |= 2;
})
.on('drag', function(d) {
d.px = d3.event.x;
d.py = d3.event.y;
if (dragged(d)) {
if (!network.force.alpha()) {
network.force.alpha(.025);
}
}
})
.on('dragend', function(d) {
if (!dragged(d)) {
selectObject(d, this);
}
d.fixed &= ~6;
});
$('#view').on('click', function(e) {
if (!$(e.target).closest('.node').length) {
deselectObject();
}
});
// TODO: add drag, mouseover, mouseout behaviors
network.node = network.svg.selectAll('.node')
.data(network.force.nodes(), function(d) {return d.id})
.enter().append('g')
.attr('class', 'node')
.attr('class', function(d) {
return 'node ' + d.type;
})
.attr('transform', function(d) {
return translate(d.x, d.y);
})
// .call(network.drag)
.on('mouseover', function(d) {})
.on('mouseout', function(d) {});
.call(network.drag)
.on('mouseover', function(d) {
if (!selected.obj) {
if (network.mouseoutTimeout) {
clearTimeout(network.mouseoutTimeout);
network.mouseoutTimeout = null;
}
highlightObject(d);
}
})
.on('mouseout', function(d) {
if (!selected.obj) {
if (network.mouseoutTimeout) {
clearTimeout(network.mouseoutTimeout);
network.mouseoutTimeout = null;
}
network.mouseoutTimeout = setTimeout(function() {
highlightObject(null);
}, 160);
}
});
// TODO: augment stroke and fill functions
network.nodeRect = network.node.append('rect')
// TODO: css for node rects
.attr('rx', 5)
.attr('ry', 5)
.attr('stroke', function(d) { return '#000'})
.attr('fill', function(d) { return '#ddf'})
// .attr('stroke', function(d) { return '#000'})
// .attr('fill', function(d) { return '#ddf'})
.attr('width', 60)
.attr('height', 24);
......
......@@ -13,7 +13,7 @@ body, html {
*/
span.title {
color: red;
color: darkblue;
font-size: 16pt;
font-style: italic;
}
......@@ -30,7 +30,7 @@ span.right {
* === DEBUGGING ======
*/
svg {
border: 1px dashed red;
/*border: 1px dashed red;*/
}
......@@ -64,36 +64,45 @@ marker#end {
-moz-transition: opacity 250ms;
}
.node text {
fill: #000;
/*differentiate between packet and optical nodes*/
svg .node.pkt rect {
fill: #77a;
}
svg .node.opt rect {
fill: #7a7;
}
svg .node text {
fill: white;
font: 10px sans-serif;
pointer-events: none;
}
.node.selected rect {
svg .node.selected rect {
filter: url(#blue-glow);
}
.link.inactive,
.node.inactive rect,
.node.inactive text {
svg .link.inactive,
svg .node.inactive rect,
svg .node.inactive text {
opacity: .2;
}
.node.inactive.selected rect,
.node.inactive.selected text {
svg .node.inactive.selected rect,
svg .node.inactive.selected text {
opacity: .6;
}
.legend {
svg .legend {
position: fixed;
}
.legend .category rect {
svg .legend .category rect {
stroke-width: 1px;
}
.legend .category text {
svg .legend .category text {
fill: #000;
font: 10px sans-serif;
pointer-events: none;
......@@ -110,15 +119,15 @@ marker#end {
#frame {
width: 100%;
height: 100%;
background-color: #ffd;
background-color: #cdf;
}
#mast {
height: 32px;
background-color: #dda;
background-color: #abe;
vertical-align: baseline;
}
#main {
background-color: #99b;
background-color: #99c;
}
......