Commit 5cbdc386 authored by Sigurdur Asgeirsson's avatar Sigurdur Asgeirsson Committed by Commit Bot

PM: Make chrome://discards/graph view ToolTips draggable.

Bug: 1068233
Change-Id: I6670998acb5fc4ecefd78d0cb2cff784e193c099
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2173869
Commit-Queue: Sigurður Ásgeirsson <siggi@chromium.org>
Reviewed-by: default avatardpapad <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#765349}
parent c261eaf4
...@@ -28,27 +28,57 @@ class ToolTip { ...@@ -28,27 +28,57 @@ class ToolTip {
* @param {GraphNode} node * @param {GraphNode} node
*/ */
constructor(div, node) { constructor(div, node) {
/** @private {GraphNode} */ /** @type {boolean} */
this.node_ = node; this.floating = true;
/** @type {number} */
this.x = node.x;
/** @type {number} */
this.y = node.y - 28;
/** @type {GraphNode} */
this.node = node;
/** @private {d3.selection} */ /** @private {d3.selection} */
this.div_ = d3.select(div) this.div_ = d3.select(div)
.append('div') .append('div')
.attr('class', 'tooltip') .attr('class', 'tooltip')
.style('opacity', 0) .style('opacity', 0)
.style('left', `${node.x}px`) .style('left', `${this.x}px`)
.style('top', `${node.y - 28}px`); .style('top', `${this.y}px`);
this.div_.append('table').append('tbody'); this.div_.append('table').append('tbody');
this.div_.transition().duration(200).style('opacity', .9); this.div_.transition().duration(200).style('opacity', .9);
/** @private {string} */ /** @private {string} */
this.description_json_ = ''; this.description_json_ = '';
// Set up a drag behavior for this object's div.
const drag = d3.drag().subject(() => this);
drag.on('start', this.onDragStart_.bind(this));
drag.on('drag', this.onDrag_.bind(this));
this.div_.call(drag);
this.onDescription(JSON.stringify({})); this.onDescription(JSON.stringify({}));
} }
nodeMoved() { nodeMoved() {
const node = this.node_; if (!this.floating) {
this.div_.style('left', `${node.x}px`).style('top', `${node.y - 28}px`); return;
}
const node = this.node;
this.x = node.x;
this.y = node.y - 28;
this.div_.style('left', `${this.x}px`).style('top', `${this.y}px`);
}
/**
* @return {!Array<number>} The [x, y] center of the ToolTip's div
* element.
*/
getCenter() {
const rect = this.div_.node().getBoundingClientRect();
return [rect.x + rect.width / 2, rect.y + rect.height / 2];
} }
goAway() { goAway() {
...@@ -92,6 +122,20 @@ class ToolTip { ...@@ -92,6 +122,20 @@ class ToolTip {
tr = tr.attr('class', d => d[1] === null ? 'heading' : 'value'); tr = tr.attr('class', d => d[1] === null ? 'heading' : 'value');
tr.selectAll('td').data(d => d).text(d => d === null ? '' : d); tr.selectAll('td').data(d => d).text(d => d === null ? '' : d);
} }
/** @private */
onDragStart_() {
this.floating = false;
}
/** @private */
onDrag_() {
this.x = d3.event.x;
this.y = d3.event.y;
this.div_.style('left', `${this.x}px`).style('top', `${this.y}px`);
graph.updateToolTipLinks();
}
} }
/** @implements {d3.ForceNode} */ /** @implements {d3.ForceNode} */
...@@ -113,9 +157,9 @@ class GraphNode { ...@@ -113,9 +157,9 @@ class GraphNode {
* @type {number|undefined} * @type {number|undefined}
*/ */
this.index; this.index;
/** @type {number|undefined} */ /** @type {number} */
this.x; this.x;
/** @type {number|undefined} */ /** @type {number} */
this.y; this.y;
/** @type {number|undefined} */ /** @type {number|undefined} */
this.vx; this.vx;
...@@ -392,6 +436,12 @@ class Graph { ...@@ -392,6 +436,12 @@ class Graph {
/** @private {d3.ForceSimulation} */ /** @private {d3.ForceSimulation} */
this.simulation_ = null; this.simulation_ = null;
/**
* A selection for the top-level <g> node that contains all tooltip links.
* @private {d3.selection}
*/
this.toolTipLinkGroup_ = null;
/** /**
* A selection for the top-level <g> node that contains all separators. * A selection for the top-level <g> node that contains all separators.
* @private {d3.selection} * @private {d3.selection}
...@@ -463,8 +513,9 @@ class Graph { ...@@ -463,8 +513,9 @@ class Graph {
this.simulation_ = simulation; this.simulation_ = simulation;
// Create the <g> elements that host nodes and links. // Create the <g> elements that host nodes and links.
// The link group is created first so that all links end up behind nodes. // The link groups are created first so that all links end up behind nodes.
const svg = d3.select(this.svg_); const svg = d3.select(this.svg_);
this.toolTipLinkGroup_ = svg.append('g').attr('class', 'toolTipLinks');
this.linkGroup_ = svg.append('g').attr('class', 'links'); this.linkGroup_ = svg.append('g').attr('class', 'links');
this.nodeGroup_ = svg.append('g').attr('class', 'nodes'); this.nodeGroup_ = svg.append('g').attr('class', 'nodes');
this.separatorGroup_ = svg.append('g').attr('class', 'separators'); this.separatorGroup_ = svg.append('g').attr('class', 'separators');
...@@ -544,6 +595,42 @@ class Graph { ...@@ -544,6 +595,42 @@ class Graph {
this.nodes_.delete(nodeId); this.nodes_.delete(nodeId);
} }
/** Updates floating tooltip positions as well as links to pinned tooltips */
updateToolTipLinks() {
const pinnedTooltips = [];
for (const node of this.nodes_.values()) {
const tooltip = node.tooltip;
if (tooltip) {
if (tooltip.floating) {
tooltip.nodeMoved();
} else {
pinnedTooltips.push(tooltip);
}
}
}
function setLineEndpoints(d) {
const line = d3.select(this);
const center = d.getCenter();
line.attr('x1', d => center[0])
.attr('y1', d => center[1])
.attr('x2', d => d.node.x)
.attr('y2', d => d.node.y);
}
const toolTipLinks =
this.toolTipLinkGroup_.selectAll('line').data(pinnedTooltips);
toolTipLinks.enter()
.append('line')
.attr('stroke', 'LightGray')
.attr('stroke-dasharray', '1')
.attr('stroke-opacity', '0.8')
.each(setLineEndpoints);
toolTipLinks.each(setLineEndpoints);
toolTipLinks.exit().remove();
}
/** /**
* @param {!GraphNode} node * @param {!GraphNode} node
* @private * @private
...@@ -766,17 +853,13 @@ class Graph { ...@@ -766,17 +853,13 @@ class Graph {
const nodes = this.nodeGroup_.selectAll('g'); const nodes = this.nodeGroup_.selectAll('g');
nodes.attr('transform', d => `translate(${d.x},${d.y})`); nodes.attr('transform', d => `translate(${d.x},${d.y})`);
for (const node of this.nodes_.values()) {
if (node.tooltip) {
node.tooltip.nodeMoved();
}
}
const lines = this.linkGroup_.selectAll('line'); const lines = this.linkGroup_.selectAll('line');
lines.attr('x1', d => d.source.x) lines.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y) .attr('y1', d => d.source.y)
.attr('x2', d => d.target.x) .attr('x2', d => d.target.x)
.attr('y2', d => d.target.y); .attr('y2', d => d.target.y);
this.updateToolTipLinks();
} }
/** /**
...@@ -955,7 +1038,7 @@ class Graph { ...@@ -955,7 +1038,7 @@ class Graph {
this.restartSimulation_(); this.restartSimulation_();
} }
} }
/* @type {?Graph} */
let graph = null; let graph = null;
function onLoad() { function onLoad() {
graph = graph =
......
...@@ -42,7 +42,6 @@ URL. As result, this document needs to be self-contained, hence inline scripts. ...@@ -42,7 +42,6 @@ URL. As result, this document needs to be self-contained, hence inline scripts.
border: 0; border: 0;
border-radius: 8px; border-radius: 8px;
padding: 2px; padding: 2px;
pointer-events: none;
position: absolute; position: absolute;
text-align: center; text-align: center;
} }
......
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