Commit c3bd6b21 authored by James Long's avatar James Long Committed by Commit Bot

Enhance visibility of edge directions in dependency visualization

A few UI controls have been added with the aim of making edge directions
easier to see in the visualization.
* Curve checkbox: Determines if edges should be curved to the right of
their direction.
* Color on hover checkbox: Determines if the edge colors should only be
shown when hovering on a node that touches those edges.
* Color scheme dropdown: Various preset color schemes determined to work
well.

Bug: 1106107
Change-Id: I15585251ad1ef3eef4b16e1ce536a1b1f527868c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2314818
Commit-Queue: James Long <yjlong@google.com>
Reviewed-by: default avatarMohamed Heikal <mheikal@chromium.org>
Reviewed-by: default avatarSamuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#791430}
parent 301f2eb6
...@@ -120,12 +120,15 @@ let D3GraphData; ...@@ -120,12 +120,15 @@ let D3GraphData;
/** /**
* Generates and returns a unique edge ID from its source/target GraphNode IDs. * Generates and returns a unique edge ID from its source/target GraphNode IDs.
*
* This is used as an SVG element ID, so it must adhere to ID requirements
* (unique, non-empty, no whitespace).
* @param {string} sourceId The ID of the source node. * @param {string} sourceId The ID of the source node.
* @param {string} targetId The ID of the target node. * @param {string} targetId The ID of the target node.
* @return {string} The ID uniquely identifying the edge source -> target. * @return {string} The ID uniquely identifying the edge source -> target.
*/ */
function getEdgeIdFromNodes(sourceId, targetId) { function getEdgeIdFromNodes(sourceId, targetId) {
return `${sourceId} > ${targetId}`; return `${sourceId}>${targetId}`;
} }
/** A directed graph. */ /** A directed graph. */
......
...@@ -4,6 +4,26 @@ ...@@ -4,6 +4,26 @@
import {GraphModel, D3GraphData} from './graph_model.js'; import {GraphModel, D3GraphData} from './graph_model.js';
/**
* Various different graph edge color schemes.
* @enum {string}
*/
const GraphEdgeColor = {
DEFAULT: 'default',
GREY_GRADIENT: 'grey-gradient',
BLUE_TO_RED: 'blue-to-red',
};
/**
* The data configuring the visualization's display.
* @typedef {Object} DisplaySettingsData
* @property {boolean} curveEdges Whether edges should be curved.
* @property {boolean} colorOnlyOnHover Whether edge colors should only be shown
* when hovering on nodes touching those edges.
* @property {GraphEdgeColor} graphEdgeColor The color of the edges.
*/
let DisplaySettingsData;
/** /**
* A container representing the visualization's node filter. Nodes included in * A container representing the visualization's node filter. Nodes included in
* the filter are allowed to be displayed on the graph. * the filter are allowed to be displayed on the graph.
...@@ -93,6 +113,13 @@ class PageModel { ...@@ -93,6 +113,13 @@ class PageModel {
this.outboundDepthData = { this.outboundDepthData = {
outboundDepth: 0, outboundDepth: 0,
}; };
/** @public {!DisplaySettingsData} */
this.displaySettingsData = {
curveEdges: true,
colorOnlyOnHover: true,
graphEdgeColor: GraphEdgeColor.DEFAULT,
};
} }
/** /**
...@@ -116,6 +143,8 @@ class PageModel { ...@@ -116,6 +143,8 @@ class PageModel {
} }
export { export {
DisplaySettingsData,
GraphEdgeColor,
NodeFilterData, NodeFilterData,
PageModel, PageModel,
}; };
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
:page-model="pageModel" :page-model="pageModel"
@[CUSTOM_EVENTS.NODE_CLICKED]="graphNodeClicked"/> @[CUSTOM_EVENTS.NODE_CLICKED]="graphNodeClicked"/>
<div id="node-details-container"> <div id="node-details-container">
<GraphDisplaySettings
:display-settings-data="pageModel.displaySettingsData"/>
<GraphSelectedNodeDetails <GraphSelectedNodeDetails
:selected-node-details-data="pageModel.selectedNodeDetailsData" :selected-node-details-data="pageModel.selectedNodeDetailsData"
@[CUSTOM_EVENTS.ADD_TO_FILTER_CLICKED]="addNodeToFilter" @[CUSTOM_EVENTS.ADD_TO_FILTER_CLICKED]="addNodeToFilter"
...@@ -45,6 +47,7 @@ import {PageModel} from '../page_model.js'; ...@@ -45,6 +47,7 @@ import {PageModel} from '../page_model.js';
import {parseClassGraphModelFromJson} from '../process_graph_json.js'; import {parseClassGraphModelFromJson} from '../process_graph_json.js';
import ClassDetailsPanel from './class_details_panel.vue'; import ClassDetailsPanel from './class_details_panel.vue';
import GraphDisplaySettings from './graph_display_settings.vue';
import GraphFilterInput from './graph_filter_input.vue'; import GraphFilterInput from './graph_filter_input.vue';
import GraphFilterItems from './graph_filter_items.vue'; import GraphFilterItems from './graph_filter_items.vue';
import GraphInboundInput from './graph_inbound_input.vue'; import GraphInboundInput from './graph_inbound_input.vue';
...@@ -57,6 +60,7 @@ import PageUrlGenerator from './page_url_generator.vue'; ...@@ -57,6 +60,7 @@ import PageUrlGenerator from './page_url_generator.vue';
const ClassGraphPage = { const ClassGraphPage = {
components: { components: {
ClassDetailsPanel, ClassDetailsPanel,
GraphDisplaySettings,
GraphFilterInput, GraphFilterInput,
GraphFilterItems, GraphFilterItems,
GraphInboundInput, GraphInboundInput,
...@@ -92,6 +96,7 @@ const ClassGraphPage = { ...@@ -92,6 +96,7 @@ const ClassGraphPage = {
CUSTOM_EVENTS: () => CUSTOM_EVENTS, CUSTOM_EVENTS: () => CUSTOM_EVENTS,
graphUpdateTriggers: function() { graphUpdateTriggers: function() {
return [ return [
this.pageModel.displaySettingsData,
this.pageModel.nodeFilterData.nodeList, this.pageModel.nodeFilterData.nodeList,
this.pageModel.inboundDepthData.inboundDepth, this.pageModel.inboundDepthData.inboundDepth,
this.pageModel.outboundDepthData.outboundDepth, this.pageModel.outboundDepthData.outboundDepth,
......
<!-- Copyright 2020 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<template>
<div id="display-settings">
<div>
<input
id="curve-edges"
v-model="displaySettingsData.curveEdges"
type="checkbox">
<label for="curve-edges">Curve graph edges</label>
</div>
<div>
<input
id="color-on-hover"
v-model="displaySettingsData.colorOnlyOnHover"
type="checkbox">
<label for="color-on-hover">Color graph edges only on node hover</label>
</div>
<label for="graph-edge-color">Graph edge color scheme:</label>
<select
id="graph-edge-color"
v-model="displaySettingsData.graphEdgeColor">
<option
v-for="edgeColor in GraphEdgeColor"
:key="edgeColor"
:value="edgeColor">
{{ edgeColor }}
</option>
</select>
</div>
</template>
<script>
import {GraphEdgeColor} from '../page_model.js';
// @vue/component
const GraphDisplaySettings = {
props: {
displaySettingsData: Object,
},
computed: {
GraphEdgeColor: () => GraphEdgeColor,
},
};
export default GraphDisplaySettings;
</script>
<style scoped>
#display-settings {
display: flex;
flex-direction: column;
margin-bottom: 10px;
}
</style>
...@@ -36,6 +36,8 @@ const GraphVisualization = { ...@@ -36,6 +36,8 @@ const GraphVisualization = {
graphUpdateTriggers: { graphUpdateTriggers: {
handler: function() { handler: function() {
this.graphView.updateGraphData(this.pageModel.getDataForD3()); this.graphView.updateGraphData(this.pageModel.getDataForD3());
this.graphView.updateDisplaySettings(
this.pageModel.displaySettingsData);
}, },
deep: true, deep: true,
}, },
...@@ -56,9 +58,8 @@ export default GraphVisualization; ...@@ -56,9 +58,8 @@ export default GraphVisualization;
</script> </script>
<style> <style>
.graph-edges line { .graph-edges path.non-hovered-edge {
stroke: #999; opacity: 0.4;
stroke-opacity: 0.6;
} }
.graph-nodes circle { .graph-nodes circle {
...@@ -71,6 +72,10 @@ export default GraphVisualization; ...@@ -71,6 +72,10 @@ export default GraphVisualization;
font-size: 12px; font-size: 12px;
} }
.graph-labels text.non-hovered-text {
opacity: 0.4;
}
.graph-nodes circle.locked { .graph-nodes circle.locked {
stroke: #000; stroke: #000;
stroke-width: 3; stroke-width: 3;
......
...@@ -56,7 +56,7 @@ export default PackageDetailsPanel; ...@@ -56,7 +56,7 @@ export default PackageDetailsPanel;
<style scoped> <style scoped>
.package-details-panel { .package-details-panel {
max-height: 400px; max-height: 300px;
overflow: hidden; overflow: hidden;
overflow-y: scroll; overflow-y: scroll;
} }
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
:page-model="pageModel" :page-model="pageModel"
@[CUSTOM_EVENTS.NODE_CLICKED]="graphNodeClicked"/> @[CUSTOM_EVENTS.NODE_CLICKED]="graphNodeClicked"/>
<div id="node-details-container"> <div id="node-details-container">
<GraphDisplaySettings
:display-settings-data="pageModel.displaySettingsData"/>
<GraphSelectedNodeDetails <GraphSelectedNodeDetails
:selected-node-details-data="pageModel.selectedNodeDetailsData" :selected-node-details-data="pageModel.selectedNodeDetailsData"
@[CUSTOM_EVENTS.ADD_TO_FILTER_CLICKED]="addNodeToFilter" @[CUSTOM_EVENTS.ADD_TO_FILTER_CLICKED]="addNodeToFilter"
...@@ -44,6 +46,7 @@ import {GraphNode} from '../graph_model.js'; ...@@ -44,6 +46,7 @@ import {GraphNode} from '../graph_model.js';
import {PageModel} from '../page_model.js'; import {PageModel} from '../page_model.js';
import {parsePackageGraphModelFromJson} from '../process_graph_json.js'; import {parsePackageGraphModelFromJson} from '../process_graph_json.js';
import GraphDisplaySettings from './graph_display_settings.vue';
import GraphFilterInput from './graph_filter_input.vue'; import GraphFilterInput from './graph_filter_input.vue';
import GraphFilterItems from './graph_filter_items.vue'; import GraphFilterItems from './graph_filter_items.vue';
import GraphInboundInput from './graph_inbound_input.vue'; import GraphInboundInput from './graph_inbound_input.vue';
...@@ -56,6 +59,7 @@ import PageUrlGenerator from './page_url_generator.vue'; ...@@ -56,6 +59,7 @@ import PageUrlGenerator from './page_url_generator.vue';
// @vue/component // @vue/component
const PackageGraphPage = { const PackageGraphPage = {
components: { components: {
GraphDisplaySettings,
GraphFilterInput, GraphFilterInput,
GraphFilterItems, GraphFilterItems,
GraphInboundInput, GraphInboundInput,
...@@ -92,6 +96,7 @@ const PackageGraphPage = { ...@@ -92,6 +96,7 @@ const PackageGraphPage = {
CUSTOM_EVENTS: () => CUSTOM_EVENTS, CUSTOM_EVENTS: () => CUSTOM_EVENTS,
graphUpdateTriggers: function() { graphUpdateTriggers: function() {
return [ return [
this.pageModel.displaySettingsData,
this.pageModel.nodeFilterData.nodeList, this.pageModel.nodeFilterData.nodeList,
this.pageModel.inboundDepthData.inboundDepth, this.pageModel.inboundDepthData.inboundDepth,
this.pageModel.outboundDepthData.outboundDepth, this.pageModel.outboundDepthData.outboundDepth,
......
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