diff options
4 files changed, 102 insertions, 42 deletions
diff --git a/tensorflow/tensorboard/components/tf-graph-common/lib/layout.ts b/tensorflow/tensorboard/components/tf-graph-common/lib/layout.ts index 81fd5ca21a..9f4e2f406b 100644 --- a/tensorflow/tensorboard/components/tf-graph-common/lib/layout.ts +++ b/tensorflow/tensorboard/components/tf-graph-common/lib/layout.ts @@ -70,10 +70,7 @@ export const PARAMS = { * element. The padding amounts are applied using an SVG transform of X and * Y coordinates. */ - padding: { - paddingTop: 40, - paddingLeft: 20 - } + padding: {paddingTop: 40, paddingLeft: 20} }, subscene: { meta: { @@ -104,6 +101,7 @@ export const PARAMS = { meta: { radius: 5, width: 60, + maxLabelWidth: 52, /** A scale for the node's height based on number of nodes inside */ height: d3.scale.linear().domain([1, 200]).range([15, 60]).clamp(true), /** The radius of the circle denoting the expand button. */ @@ -113,8 +111,9 @@ export const PARAMS = { op: { width: 15, height: 6, - radius: 3, // for making annotation touching ellipse - labelOffset: -8 + radius: 3, // for making annotation touching ellipse + labelOffset: -8, + maxLabelWidth: 30 }, /** Size of series nodes. */ series: { @@ -138,7 +137,7 @@ export const PARAMS = { // ellipses. width: 24, height: 8, - radius: 10, // Forces annotations to center line. + radius: 10, // Forces annotations to center line. labelOffset: -10, }, }, @@ -155,16 +154,9 @@ export const PARAMS = { }, shortcutSize: { /** Size of shortcuts for op nodes */ - op: { - width: 10, - height: 4 - }, + op: {width: 10, height: 4}, /** Size of shortcuts for meta nodes */ - meta: { - width: 12, - height: 4, - radius: 1 - }, + meta: {width: 12, height: 4, radius: 1}, /** Size of shortcuts for series nodes */ series: { width: 14, @@ -182,15 +174,10 @@ export const PARAMS = { yOffset: 3, /** X-space between each annotation-node and its label. */ labelOffset: 2, - /** Estimate max width for annotation label */ - labelWidth: 35 - }, - constant: { - size: { - width: 4, - height: 4 - } + /** Defines the max width for annotation label */ + maxLabelWidth: 120 }, + constant: {size: {width: 4, height: 4}}, series: { /** Maximum number of repeated item for unexpanded series node. */ maxStackCount: 3, @@ -205,7 +192,7 @@ export const PARAMS = { */ towerStackOffsetRatio: 0.5 }, - minimap : { + minimap: { /** The maximum width/height the minimap can have. */ size: 150 } diff --git a/tensorflow/tensorboard/components/tf-graph-common/lib/scene/annotation.ts b/tensorflow/tensorboard/components/tf-graph-common/lib/scene/annotation.ts index d4855cdc57..ba308e6934 100644 --- a/tensorflow/tensorboard/components/tf-graph-common/lib/scene/annotation.ts +++ b/tensorflow/tensorboard/components/tf-graph-common/lib/scene/annotation.ts @@ -129,24 +129,22 @@ function buildShape(aGroup, a: render.Annotation) { function addAnnotationLabelFromNode(aGroup, a: render.Annotation) { let namePath = a.node.name.split('/'); let text = namePath[namePath.length - 1]; - let shortenedText = text.length > 8 ? text.substring(0, 8) + '...' : text; - return addAnnotationLabel(aGroup, shortenedText, a, null, text); + return addAnnotationLabel(aGroup, text, a, null); } -function addAnnotationLabel(aGroup, label, a, additionalClassNames, - fullLabel?) { +function addAnnotationLabel( + aGroup, label: string, a: render.Annotation, additionalClassNames) { let classNames = Class.Annotation.LABEL; if (additionalClassNames) { classNames += ' ' + additionalClassNames; } - let titleText = fullLabel ? fullLabel : label; - return aGroup.append('text') - .attr('class', classNames) - .attr('dy', '.35em') - .attr('text-anchor', a.isIn ? 'end' : 'start') - .text(label) - .append('title') - .text(titleText); + let txtElement = aGroup.append('text') + .attr('class', classNames) + .attr('dy', '.35em') + .attr('text-anchor', a.isIn ? 'end' : 'start') + .text(label); + + return tf.graph.scene.node.enforceLabelWidth(txtElement, -1); } function addInteraction(selection, d: render.RenderNodeInfo, @@ -185,7 +183,7 @@ function addInteraction(selection, d: render.RenderNodeInfo, * @param aGroup selection of a 'g.annotation' element. * @param d Host node data. * @param a annotation node data. - * @param scene <tf-graph-scene> polymer element. + * @param sceneElement <tf-graph-scene> polymer element. */ function update(aGroup, d: render.RenderNodeInfo, a: render.Annotation, sceneElement) { diff --git a/tensorflow/tensorboard/components/tf-graph-common/lib/scene/node.ts b/tensorflow/tensorboard/components/tf-graph-common/lib/scene/node.ts index 9216c27834..1c585c23f5 100644 --- a/tensorflow/tensorboard/components/tf-graph-common/lib/scene/node.ts +++ b/tensorflow/tensorboard/components/tf-graph-common/lib/scene/node.ts @@ -364,9 +364,84 @@ function labelBuild(nodeGroup, renderNodeInfo: render.RenderNodeInfo, let scale = getLabelFontScale(sceneElement); label.attr('font-size', scale(text.length) + 'px'); } - label.text(text); + + let txtElement = <d3.Selection<any>>label.text(text); + enforceLabelWidth(txtElement, renderNodeInfo.node.type, renderNodeInfo); return label; -}; +} +/** + * This function shortens text which would exceed the maximum pixel width of + * a label. + * + * @param txtElementSelection The text element containing the label's text as d3 + * selection. + * @param nodeType The type of the node the label belongs to. If the node is + * an annotation, the value is -1. Label widths are defined in + * layout.PARAMS.nodeSize.{meta|op|...}.maxLabelWidth for nodes and + * layout.PARAMS.annotations.labelWidth for annotations. + * @param renderNodeInfo The render information about the node, required to + * determine whether META nodes are collapsed or expanded. + */ +export function enforceLabelWidth( + txtElementSelection: d3.Selection<any>, nodeType: NodeType | number, + renderNodeInfo?: render.RenderNodeInfo) { + // Get text element itself and its on-screen width. + let txtNode = <SVGTextElement>txtElementSelection.node(); + let computedTxtLength = txtNode.getComputedTextLength(); + let labelContent = txtNode.textContent; + + // Get maximum length from settings. + let maxLength = null; + switch (nodeType) { + case NodeType.META: + if (renderNodeInfo && !renderNodeInfo.expanded) { // Only trim text if + // node expanded. + maxLength = layout.PARAMS.nodeSize.meta.maxLabelWidth; + } + break; + + case NodeType.OP: + maxLength = layout.PARAMS.nodeSize.op.maxLabelWidth; + break; + + case -1: + maxLength = layout.PARAMS.annotations.maxLabelWidth; + break; + + default: + break; + } + + // Return if no max length provided for node type, or current label length is + // less than or equal to the provided length limit. + if (maxLength === null || computedTxtLength <= maxLength) { + return; + } + + // Find the index of the character which exceeds the width. + // getSubStringLength performs far better than getComputedTextLength, and + // results in a 3x speed-up on average. + let index = 1; + while (txtNode.getSubStringLength(0, index) < maxLength) { + index++; + } + + // Shorten the label starting at the string length known to be one + // character above max pixel length. + // When shortened the original label's substring is concatenated with + // '...', baseText contains the substring not including the '...'. + let baseText = <string>txtNode.textContent.substr(0, index); + do { + baseText = baseText.substr(0, baseText.length - 1); + + // Recompute text length. + txtNode.textContent = baseText + '...'; + computedTxtLength = txtNode.getComputedTextLength(); + } while (computedTxtLength > maxLength && baseText.length > 0); + + // Add tooltip with full name and return. + return txtElementSelection.append('title').text(labelContent); +} /** * d3 scale used for sizing font of labels, used by labelBuild, diff --git a/tensorflow/tensorboard/components/tf-graph/tf-graph-scene.html b/tensorflow/tensorboard/components/tf-graph/tf-graph-scene.html index bbdf6db22a..332f36d7c1 100644 --- a/tensorflow/tensorboard/components/tf-graph/tf-graph-scene.html +++ b/tensorflow/tensorboard/components/tf-graph/tf-graph-scene.html @@ -56,8 +56,8 @@ stroke-width: 3; } -:content .annotation.meta.selected > .nodeshape > rect, -:content .annotation.meta.selected > .annotation-node > rect { +::content .annotation.meta.selected > .nodeshape > rect, +::content .annotation.meta.selected > .annotation-node > rect { stroke: red; stroke-width: 2; } |