Commit 43d588cc authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbolizer] Eye candy that helps readability

- Turbolizer highlights input and output nodes on hover.
- The three panes support resizing now (snap to side still works).

Bug: 
Change-Id: Ida1513fd714a02ab772885ea1fdf6d9da8d540f6
Reviewed-on: https://chromium-review.googlesource.com/837068
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarDaniel Clifford <danno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50523}
parent 73ba170a
......@@ -164,8 +164,6 @@ class CodeView extends View {
}
}
}
view.resizeToParent();
}
deleteContent() {}
......
......@@ -706,6 +706,7 @@ class GraphView extends View {
.on("mousedown", function(d){
graph.pathMouseDown.call(graph, d3.select(this), d);
})
.attr("adjacentToHover", "false");
// Set the correct styles on all of the paths
visibleEdges.classed('value', function(e) {
......@@ -740,7 +741,8 @@ class GraphView extends View {
var newGs = graph.visibleNodes.enter()
.append("g");
newGs.classed("control", function(n) { return n.isControl(); })
newGs.classed("turbonode", function(n) { return true; })
.classed("control", function(n) { return n.isControl(); })
.classed("live", function(n) { return n.isLive(); })
.classed("dead", function(n) { return !n.isLive(); })
.classed("javascript", function(n) { return n.isJavaScript(); })
......@@ -754,6 +756,34 @@ class GraphView extends View {
.on("mouseup", function(d){
graph.nodeMouseUp.call(graph, d3.select(this), d);
})
.on('mouseover', function(d){
var nodeSelection = d3.select(this);
let node = graph.nodeMap[d.id];
let adjInputEdges = graph.visibleEdges.filter(e => { return e.target === node; });
let adjOutputEdges = graph.visibleEdges.filter(e => { return e.source === node; });
adjInputEdges.attr('relToHover', "input");
adjOutputEdges.attr('relToHover', "output");
let adjInputNodes = adjInputEdges.data().map(e => e.source);
graph.visibleNodes.data(adjInputNodes, function(d) {
return d.id;
}).attr('relToHover', "input");
let adjOutputNodes = adjOutputEdges.data().map(e => e.target);
graph.visibleNodes.data(adjOutputNodes, function(d) {
return d.id;
}).attr('relToHover', "output");
graph.updateGraphVisibility();
})
.on('mouseout', function(d){
var nodeSelection = d3.select(this);
let node = graph.nodeMap[d.id];
let adjEdges = graph.visibleEdges.filter(e => { return e.target === node || e.source === node; });
adjEdges.attr('relToHover', "none");
let adjNodes = adjEdges.data().map(e => e.target).concat(adjEdges.data().map(e => e.source));
let nodes = graph.visibleNodes.data(adjNodes, function(d) {
return d.id;
}).attr('relToHover', "none");
graph.updateGraphVisibility();
})
.call(graph.drag);
newGs.append("rect")
......
......@@ -4,13 +4,14 @@
<title>Turbolizer</title>
<link rel="stylesheet" href="turbo-visualizer.css" />
</head>
<body width="100%">
<body>
<div id="left">
<div id='source-text'>
<pre id='source-text-pre'\>
</div>
</div>
<div id="middle">
<div class="resizer-left"></div>
<div id="middle" class="resizable-pane">
<div id="graph-toolbox-anchor">
<span id="graph-toolbox">
<input id="layout" type="image" title="layout graph" src="layout-icon.png"
......@@ -47,12 +48,13 @@
<pre id="schedule-text-pre" class='prettyprint prettyprinted'>
<ul id="schedule-list" class='nolinenums noindent'>
</ul>
</pre>
</pre>
</div>
<div id='text-placeholder' width="0px" height="0px" style="position: absolute; top:100000px;" ><svg><text text-anchor="right">
<tspan white-space="inherit" id="text-measure"/>
</text></svg></div>
</div>
<div class="resizer-right"></div>
<div id="right">
<div id='disassembly'>
<pre id='disassembly-text-pre' class='prettyprint prettyprinted'>
......@@ -63,15 +65,15 @@
</div>
<div id="source-collapse" class="collapse-pane">
<input id="source-expand" type="image" title="show source"
src="right-arrow.png" class="button-input-invisible">
src="right-arrow.png" class="button-input invisible">
<input id="source-shrink" type="image" title="hide source"
src="left-arrow.png" class="button-input">
</div>
<div id="disassembly-collapse" class="collapse-pane">
<input id="disassembly-expand" type="image" title="show disassembly"
src="left-arrow.png" class="button-input">
<input id="disassembly-shrink" type="image" title="hide disassembly"
src="right-arrow.png" class="button-input-invisible">
src="left-arrow.png" class="button-input invisible">
<input id="disassembly-shrink" type="image" title="hide disassembly"
src="right-arrow.png" class="button-input">
</div>
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
......
......@@ -41,10 +41,8 @@
outline: none;
}
.button-input-invisible {
vertical-align: middle;
width: 0px;
visibility: hidden;
.invisible {
display: none;
}
......@@ -57,9 +55,12 @@
!important
}
body {
margin: 0;
padding: 0;
height: 100vh;
width: 100vw;
overflow:hidden;
-webkit-touch-callout: none;
-webkit-user-select: none;
......@@ -69,8 +70,8 @@ body {
user-select: none;
}
p {
text-align: center;
p {
text-align: center;
overflow: overlay;
position: relative;
}
......@@ -97,21 +98,47 @@ div.scrollable {
overflow-y: _croll; overflow-x: hidden;
}
g.control rect {
g.turbonode[relToHover="input"] rect {
stroke: #67e62c;
stroke-width: 16px;
}
g.turbonode[relToHover="output"] rect {
stroke: #d23b14;
stroke-width: 16px;
}
path[relToHover="input"] {
stroke: #67e62c;
stroke-width: 16px;
}
path[relToHover="output"] {
stroke: #d23b14;
stroke-width: 16px;
}
g.turbonode:hover rect {
stroke: #000000;
stroke-width: 7px;
}
g.control rect {
fill: #EFCC00;
stroke: #080808;
stroke-width: 5px;
}
g.javascript rect {
g.javascript rect {
fill: #DD7E6B;
}
g.simplified rect {
g.simplified rect {
fill: #3C78D8;
}
g.machine rect {
g.machine rect {
fill: #6AA84F;
}
......@@ -156,47 +183,14 @@ circle.halfFilledBubbleStyle:hover {
stroke-width: 3px;
}
path.effect {
path {
fill: none;
stroke: #080808;
stroke-width: 4px;
cursor: default;
}
path.effect:hover {
stroke-width: 6px;
}
path.control {
fill: none;
stroke: #080808;
stroke-width: 4px;
cursor: default;
}
path.control:hover {
stroke-width: 6px;
}
path.value {
fill: none;
stroke: #888888;
stroke-width: 4px;
cursor: default;
}
path.value:hover {
stroke-width: 6px;
}
path.frame-state {
fill: none;
stroke: #080808;
stroke-width: 4px;
cursor: default;
}
path.frame-state:hover{
path:hover {
stroke-width: 6px;
}
......@@ -246,33 +240,20 @@ span.linkable-text:hover {
font-weight: bold;
}
#left {
float: left; height: 100%; background-color: #FFFFFF;
-webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
transition: all .3s ease-in-out;
transition-property: width;
}
#middle {
float:left; height: 100%; background-color: #F8F8F8;
-webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
transition: all .3s ease-in-out;
transition-property: width;
float:left; height: 100%; background-color: #F8F8F8;
}
#right {
float: right; background-color: #FFFFFF;
-webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
transition: all .3s ease-in-out;
transition-property: width;
float: right; background-color: #FFFFFF;
}
#disassembly-collapse {
right: 0;
}
......@@ -288,7 +269,7 @@ span.linkable-text:hover {
#graph-toolbox {
position: relative;
top: 1em;
left: 0.7em;
left: 25px;
border: 2px solid #eee8d5;
border-radius: 5px;
padding: 0.7em;
......@@ -337,4 +318,44 @@ tspan {
text {
dominant-baseline: text-before-edge;
}
.resizer-left {
position:absolute;
width: 4px;
height:100%;
background: #a0a0a0;
cursor: pointer;
}
.resizer-left.snapped {
width: 12px;
}
.resizer-left:hover {
background: orange;
}
.resizer-left.dragged {
background: orange;
}
.resizer-right {
position:absolute;
width: 4px;
height:100%;
background: #a0a0a0;
cursor: pointer;
}
.resizer-right.snapped {
width: 12px;
}
.resizer-right:hover {
background: orange;
}
.resizer-right.dragged {
background: orange;
}
\ No newline at end of file
// Copyright 2014 the V8 project authors. All rights reserved.
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
document.onload = (function(d3){
"use strict";
var jsonObj;
var sourceExpandClassList = document.getElementById(SOURCE_EXPAND_ID).classList;
var sourceCollapseClassList = document.getElementById(SOURCE_COLLAPSE_ID).classList;
var sourceExpanded = sourceCollapseClassList.contains(COLLAPSE_PANE_BUTTON_VISIBLE);
var disassemblyExpandClassList = document.getElementById(DISASSEMBLY_EXPAND_ID).classList;
var disassemblyCollapseClassList = document.getElementById(DISASSEMBLY_COLLAPSE_ID).classList;
var disassemblyExpanded = disassemblyCollapseClassList.contains(COLLAPSE_PANE_BUTTON_VISIBLE);
var svg = null;
var graph = null;
var schedule = null;
var empty = null;
var currentPhaseView = null;
var disassemblyView = null;
var sourceView = null;
var selectionBroker = null;
class Snapper {
function updatePanes() {
if (sourceExpanded) {
if (disassemblyExpanded) {
d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "30%");
d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "40%");
d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "30%");
} else {
d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "50%");
d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "50%");
d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "0%");
}
} else {
if (disassemblyExpanded) {
d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "0%");
d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "50%");
d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "50%");
} else {
d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "0%");
d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "100%");
d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "0%");
}
}
constructor(resizer) {
let snapper = this;
snapper.resizer = resizer;
snapper.sourceExpand = d3.select("#" + SOURCE_EXPAND_ID);
snapper.sourceCollapse = d3.select("#" + SOURCE_COLLAPSE_ID);
snapper.disassemblyExpand = d3.select("#" + DISASSEMBLY_EXPAND_ID);
snapper.disassemblyCollapse = d3.select("#" + DISASSEMBLY_COLLAPSE_ID);
d3.select("#source-collapse").on("click", function(){
resizer.snapper.toggleSourceExpanded();
});
d3.select("#disassembly-collapse").on("click", function(){
resizer.snapper.toggleDisassemblyExpanded();
});
}
function getLastExpandedState(type, default_state) {
getLastExpandedState(type, default_state) {
var state = window.sessionStorage.getItem("expandedState-"+type);
if (state === null) return default_state;
return state === 'true';
}
function setLastExpandedState(type, state) {
setLastExpandedState(type, state) {
window.sessionStorage.setItem("expandedState-"+type, state);
}
function toggleSourceExpanded() {
setSourceExpanded(!sourceExpanded);
toggleSourceExpanded() {
this.setSourceExpanded(!this.sourceExpand.classed("invisible"));
}
sourceExpandUpdate(newState) {
this.setLastExpandedState("source", newState);
this.sourceExpand.classed("invisible", newState);
this.sourceCollapse.classed("invisible", !newState);
}
function setSourceExpanded(newState) {
sourceExpanded = newState;
setLastExpandedState("source", newState);
updatePanes();
setSourceExpanded(newState) {
if (this.sourceExpand.classed("invisible") === newState) return;
this.sourceExpandUpdate(newState);
let resizer = this.resizer;
if (newState) {
sourceCollapseClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
sourceCollapseClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
sourceExpandClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
sourceExpandClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
resizer.sep_left = resizer.sep_left_snap;
resizer.sep_left_snap = 0;
} else {
sourceCollapseClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
sourceCollapseClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
sourceExpandClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
sourceExpandClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
resizer.sep_left_snap = resizer.sep_left;
resizer.sep_left = 0;
}
resizer.updatePanes();
}
function toggleDisassemblyExpanded() {
setDisassemblyExpanded(!disassemblyExpanded);
toggleDisassemblyExpanded() {
this.setDisassemblyExpanded(!this.disassemblyExpand.classed("invisible"));
}
function setDisassemblyExpanded(newState) {
disassemblyExpanded = newState;
setLastExpandedState("disassembly", newState);
updatePanes();
disassemblyExpandUpdate(newState) {
this.setLastExpandedState("disassembly", newState);
this.disassemblyExpand.classed("invisible", newState);
this.disassemblyCollapse.classed("invisible", !newState);
}
setDisassemblyExpanded(newState) {
console.log(newState)
if (this.disassemblyExpand.classed("invisible") === newState) return;
this.disassemblyExpandUpdate(newState);
let resizer = this.resizer;
if (newState) {
disassemblyCollapseClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
disassemblyCollapseClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
disassemblyExpandClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
disassemblyExpandClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
resizer.sep_right = resizer.sep_right_snap;
resizer.sep_right_snap = resizer.client_width;
console.log("set expand")
} else {
disassemblyCollapseClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
disassemblyCollapseClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
disassemblyExpandClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
disassemblyExpandClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
resizer.sep_right_snap = resizer.sep_right;
resizer.sep_right = resizer.client_width;
console.log("set collapse")
}
resizer.updatePanes();
}
panesUpated() {
this.sourceExpandUpdate(this.resizer.sep_left > this.resizer.dead_width);
this.disassemblyExpandUpdate(this.resizer.sep_right <
(this.resizer.client_width - this.resizer.dead_width));
}
}
class Resizer {
constructor(panes_updated_callback, dead_width) {
let resizer = this;
resizer.snapper = new Snapper(resizer)
resizer.panes_updated_callback = panes_updated_callback;
resizer.dead_width = dead_width
resizer.client_width = d3.select("body").node().getBoundingClientRect().width;
resizer.left = d3.select("#" + SOURCE_PANE_ID);
resizer.middle = d3.select("#" + INTERMEDIATE_PANE_ID);
resizer.right = d3.select("#" + GENERATED_PANE_ID);
resizer.resizer_left = d3.select('.resizer-left');
resizer.resizer_right = d3.select('.resizer-right');
resizer.sep_left = resizer.client_width/3;
resizer.sep_right = resizer.client_width/3*2;
resizer.sep_left_snap = 0;
resizer.sep_right_snap = 0;
// Offset to prevent resizers from sliding slightly over one another.
resizer.sep_width_offset = 7;
let dragResizeLeft = d3.behavior.drag()
.on('drag', function() {
let x = d3.mouse(this.parentElement)[0];
resizer.sep_left = Math.min(Math.max(0,x), resizer.sep_right-resizer.sep_width_offset);
resizer.updatePanes();
})
.on('dragstart', function() {
resizer.resizer_left.classed("dragged", true);
let x = d3.mouse(this.parentElement)[0];
if (x > dead_width) {
resizer.sep_left_snap = resizer.sep_left;
}
})
.on('dragend', function() {
resizer.resizer_left.classed("dragged", false);
});
resizer.resizer_left.call(dragResizeLeft);
let dragResizeRight = d3.behavior.drag()
.on('drag', function() {
let x = d3.mouse(this.parentElement)[0];
resizer.sep_right = Math.max(resizer.sep_left+resizer.sep_width_offset, Math.min(x, resizer.client_width));
resizer.updatePanes();
})
.on('dragstart', function() {
resizer.resizer_right.classed("dragged", true);
let x = d3.mouse(this.parentElement)[0];
if (x < (resizer.client_width-dead_width)) {
resizer.sep_right_snap = resizer.sep_right;
}
})
.on('dragend', function() {
resizer.resizer_right.classed("dragged", false);
});;
resizer.resizer_right.call(dragResizeRight);
window.onresize = function(){
resizer.updateWidths();
/*fitPanesToParents();*/
resizer.updatePanes();
};
}
updatePanes() {
let left_snapped = this.sep_left === 0;
let right_snapped = this.sep_right >= this.client_width - 1;
this.resizer_left.classed("snapped", left_snapped);
this.resizer_right.classed("snapped", right_snapped);
this.left.style('width', this.sep_left + 'px');
this.middle.style('width', (this.sep_right-this.sep_left) + 'px');
this.right.style('width', (this.client_width - this.sep_right) + 'px');
this.resizer_left.style('left', this.sep_left + 'px');
this.resizer_right.style('right', (this.client_width - this.sep_right - 1) + 'px');
this.snapper.panesUpated();
this.panes_updated_callback();
}
updateWidths() {
this.client_width = d3.select("body").node().getBoundingClientRect().width;
this.sep_right = Math.min(this.sep_right, this.client_width);
this.sep_left = Math.min(Math.max(0, this.sep_left), this.sep_right);
}
}
document.onload = (function(d3){
"use strict";
var jsonObj;
var svg = null;
var graph = null;
var schedule = null;
var empty = null;
var currentPhaseView = null;
var disassemblyView = null;
var sourceView = null;
var selectionBroker = null;
let resizer = new Resizer(panesUpdatedCallback, 100);
function panesUpdatedCallback() {
graph.fitGraphViewToWindow();
}
function hideCurrentPhase() {
......@@ -128,8 +220,6 @@ document.onload = (function(d3){
d3.select("#right").classed("scrollable", false);
graph.fitGraphViewToWindow();
disassemblyView.resizeToParent();
sourceView.resizeToParent();
d3.select("#left").classed("scrollable", true);
d3.select("#right").classed("scrollable", true);
......@@ -138,21 +228,6 @@ document.onload = (function(d3){
selectionBroker = new SelectionBroker();
function initializeHandlers(g) {
d3.select("#source-collapse").on("click", function(){
toggleSourceExpanded(true);
setTimeout(function(){
g.fitGraphViewToWindow();
}, 300);
});
d3.select("#disassembly-collapse").on("click", function(){
toggleDisassemblyExpanded();
setTimeout(function(){
g.fitGraphViewToWindow();
}, 300);
});
window.onresize = function(){
fitPanesToParents();
};
d3.select("#hidden-file-upload").on("change", function() {
if (window.File && window.FileReader && window.FileList) {
var uploadFile = this.files[0];
......@@ -238,9 +313,11 @@ document.onload = (function(d3){
initializeHandlers(graph);
setSourceExpanded(getLastExpandedState("source", true));
setDisassemblyExpanded(getLastExpandedState("disassembly", false));
resizer.snapper.setSourceExpanded(resizer.snapper.getLastExpandedState("source", true));
resizer.snapper.setDisassemblyExpanded(resizer.snapper.getLastExpandedState("disassembly", false));
displayPhaseView(empty, null);
fitPanesToParents();
resizer.updatePanes();
})(window.d3);
......@@ -18,21 +18,9 @@ class View {
show(data, rememberedSelection) {
this.parentNode.appendChild(this.divElement[0][0]);
this.initializeContent(data, rememberedSelection);
this.resizeToParent();
this.divElement.attr(VISIBILITY, 'visible');
}
resizeToParent() {
var view = this;
var documentElement = document.documentElement;
var y;
if (this.parentNode.clientHeight)
y = Math.max(this.parentNode.clientHeight, documentElement.clientHeight);
else
y = documentElement.clientHeight;
this.parentNode.style.height = y + 'px';
}
hide() {
this.divElement.attr(VISIBILITY, 'hidden');
this.deleteContent();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment