aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/tensorboard/components/tf-multi-checkbox
diff options
context:
space:
mode:
Diffstat (limited to 'tensorflow/tensorboard/components/tf-multi-checkbox')
-rw-r--r--tensorflow/tensorboard/components/tf-multi-checkbox/demo/index.html162
-rw-r--r--tensorflow/tensorboard/components/tf-multi-checkbox/tf-multi-checkbox.html228
2 files changed, 390 insertions, 0 deletions
diff --git a/tensorflow/tensorboard/components/tf-multi-checkbox/demo/index.html b/tensorflow/tensorboard/components/tf-multi-checkbox/demo/index.html
new file mode 100644
index 0000000000..e5661b98bc
--- /dev/null
+++ b/tensorflow/tensorboard/components/tf-multi-checkbox/demo/index.html
@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../bower_components/d3/d3.js"></script>
+<link rel="import" href="../tf-multi-checkbox.html">
+<link rel="import" href="../../tf-event-dashboard/tf-color-scale.html">
+<link rel="stylesheet" type="text/css" href="../../../lib/css/global.css">
+
+</head>
+<body>
+<script>
+var seed = 1;
+function random() {
+ var x = Math.sin(seed++) * 10000;
+ return x - Math.floor(x);
+}
+</script>
+<style>
+</style>
+
+<dom-module id="mc-demo">
+ <template>
+ <tf-multi-checkbox
+ id="multiCheckbox"
+ names="[[names]]"
+ tooltips="[[_tooltips]]"
+ class-scale="[[classScale]]"
+ highlights="[[highlights]]"
+ ></tf-multi-checkbox>
+ <tf-color-scale
+ id="colorScale"
+ runs="[[names]]"
+ out-class-scale="{{classScale}}"
+ ></tf-color-scale>
+ <style>
+ </style>
+ </template>
+ <script>
+
+ function randomTooltip() {
+ var s = "";
+ while (random() < 0.8) {
+ s += String(10*random())[0];
+ }
+ return s;
+ }
+ Polymer({
+ is: "mc-demo",
+ properties: {
+ names: Array,
+ tooltips: Object,
+ autoGenerateTooltips: {value: true},
+ _tooltips: Object,
+ classScale: Function,
+ highlights: Array,
+ },
+ observers: [
+ 'autogenerate(names, autoGenerateTooltips)',
+ 'randomHighlights(names)'
+ ],
+ autogenerate: function(names, autoGenerateTooltips) {
+ if (autoGenerateTooltips) {
+ var tooltips = {};
+ names.forEach(function(n) {
+ if (random() > 0.5) {
+ tooltips[n] = randomTooltip();
+ }
+ });
+ this._tooltips = tooltips;
+ }
+ },
+ randomHighlights: function(names) {
+ var h = [];
+ names.forEach(function(n) {
+ if (random() > 0.6) {
+ h.push(n);
+ }
+ });
+ this.highlights = h;
+ }
+ });
+ </script>
+</dom-module>
+
+<dom-module id="x-demo">
+<style>
+.small {
+ width: 200px;
+ height: 500px;
+}
+.large {
+ width: 500px;
+ height: 900px;
+}
+html,body {
+ height: 100%;
+}
+mc-demo {
+ padding: 5px;
+ border: 1px solid var(--paper-red-500);
+ display: inline-block;
+}
+</style>
+<template>
+ <div class="demo-block">
+ <mc-demo id="demo1" class="small" names="[[long_names]]"></mc-demo>
+ <mc-demo class="small" names="[[many_names]]"></mc-demo>
+ <mc-demo class="small" names="[[many_long_names]]"></mc-demo>
+ </div>
+
+ <div class="demo-block">
+ <mc-demo class="large" names="[[long_names]]"></mc-demo>
+ <mc-demo class="large" names="[[many_names]]"></mc-demo>
+ <mc-demo class="large" names="[[many_long_names]]"></mc-demo>
+ </div>
+
+</template>
+<script>
+
+function long_names() {
+ return [
+ "foo_bar very long name with spaces",
+ "the quick brown fox jumped over the lazy dog",
+ "supercalifragilisticexpialodcious/bar/foo/zod/longer/longer",
+ ];
+}
+
+function many_names() {
+ var out = [];
+ for (var i=0; i<20; i++) {
+ out.push("foo_bar-" + i);
+ out.push("bar_zod_bing-" + i);
+ out.push("lol-" + i);
+ }
+ return out;
+}
+
+function many_long_names() {
+ var out = [];
+ for (var i=0; i<20; i++) {
+ out.push("foo_bar very very very long some spaces though-" + i);
+ out.push("bar_zod_bing_bas_womp_wub_wub_dub_wub_wub-" + i);
+ out.push("rightly_to_be_great_is_not_to_stir_without_great_argument_but_greatly_to_find_quarrel_in_a_straw_when_honors_at_the_stake-" + i);
+ }
+ return out;
+}
+
+Polymer({
+ is: "x-demo",
+ properties: {
+ long_names: {type: Array, value: long_names},
+ many_names: {type: Array, value: many_names},
+ many_long_names: {type: Array, value: many_long_names},
+},
+});
+</script>
+</dom-module>
+
+<x-demo id="demo"></x-demo>
+</body>
+</html>
diff --git a/tensorflow/tensorboard/components/tf-multi-checkbox/tf-multi-checkbox.html b/tensorflow/tensorboard/components/tf-multi-checkbox/tf-multi-checkbox.html
new file mode 100644
index 0000000000..a5447e8f5e
--- /dev/null
+++ b/tensorflow/tensorboard/components/tf-multi-checkbox/tf-multi-checkbox.html
@@ -0,0 +1,228 @@
+<link rel="import" href="../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../bower_components/paper-checkbox/paper-checkbox.html">
+<link rel="import" href="../imports/lodash.html">
+<link rel="import" href="../tf-dashboard-common/scrollbar-style.html">
+<link rel="import" href="../tf-dashboard-common/run-color-style.html">
+<!--
+tf-multi-checkbox creates a list of checkboxes that can be used to toggle on or off
+a large number of values. Each checkbox displays a name, and may also have an
+assosciated tooltip value. Checkboxes can be highlighted, hidden, and re-ordered.
+
+tf-multi-checkbox assumes that the names may be very long compared to the width
+of the checkbox, and the number of names may also be very large, and works to
+handle these situations gracefully.
+
+API:
+
+Properties in:
+names: The string names to associate with checkboxes.
+tooltips: An object mapping from name to tooltip value.
+tooltipOrderer: A function that is used to compute how to order the names based
+on tooltip values (when available). If tooltip values and a tooltip orderer are
+present, the tooltipOrderer computes a numeric value for each tooltip, tooltips
+with higher values are ordered first, tooltips with equal values are ordered
+lexicogrpahically, and tooltips without a value are placed last. If the
+tooltipOrderer is set to a falsey value (eg null), then the names are not
+re-ordered based on tooltip value.
+classScale: A function that maps from name to class name, which is applied as
+the special property color-class. This is intended to be used to color the names.
+hideMissingTooltips: If set, then when tooltips are present, any names that do
+not have an associate non-empty tooltip value will be hidden.
+
+Properties out:
+outSelected: An array of names that the user has checked.
+If the user does not interact, everything will be checked.
+
+-->
+
+<dom-module id="tf-multi-checkbox">
+ <style include="scrollbar-style"></style>
+ <style include="run-color-style"></style>
+
+ <template>
+ <div id="outer-container" class="scrollbar">
+ <template
+ is="dom-repeat"
+ items="[[names]]"
+ sort="[[_tooltipComparator(tooltips, tooltipOrderer)]]"
+ >
+ <div
+ class="run-row"
+ color-class$="[[_applyColorClass(item, classScale)]]"
+ null-tooltip$="[[_isNullTooltip(item, tooltips)]]"
+ highlight$="[[_isHighlighted(item, highlights.*)]]"
+ >
+ <div class="checkbox-container vertical-align-container">
+ <paper-checkbox
+ class="checkbox vertical-align-center"
+ name="[[item]]"
+ checked$="[[_isChecked(item,outSelected.*)]]"
+ on-change="_checkboxChange"
+ ></paper-checkbox>
+ </div>
+ <div class="item-label-container">
+ <span>[[item]]</span>
+ </div>
+ <div class="tooltip-value-container vertical-align-container">
+ <span class="vertical-align-top">[[_lookupTooltip(item,tooltips)]]</span>
+ </div>
+ </div>
+ </template>
+ </div>
+ <style>
+ :host {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ }
+ #outer-container {
+ overflow-y: scroll;
+ overflow-x: hidden;
+ width: 100%;
+ flex-grow: 1;
+ flex-shrink: 1;
+ word-wrap: break-word;
+ }
+ .run-row {
+ padding-top: 5px;
+ padding-bottom: 5px;
+ display: flex;
+ flex-direction: row;
+ font-size: 13px;
+ }
+ .checkbox-container {
+ flex-grow: 0;
+ flex-shrink: 0;
+ }
+ .checkbox {
+ padding-left: 2px;
+ width: 32px;
+ }
+ .item-label-container {
+ flex-grow: 1;
+ flex-shrink: 1;
+ width: 0px; /* hack to get the flex-grow to work properly */
+ }
+ .tooltip-value-container {
+ display: flex;
+ justify-content: center;
+ flex-grow: 0;
+ flex-shrink: 0;
+ text-align:right;
+ padding-left: 2px;
+ }
+ .vertical-align-container {
+ display: flex;
+ justify-content: center;
+ }
+ .vertical-align-container .vertical-align-center {
+ align-self: center;
+ }
+ .vertical-align-container .vertical-align-top {
+ align-self: start;
+ }
+ [null-tooltip] {
+ display: none;
+ }
+ [highlight] {
+ font-weight: bold;
+ }
+ </style>
+ </template>
+
+ <script>
+ Polymer({
+ is: "tf-multi-checkbox",
+ properties: {
+ names: Array,
+ tooltipOrderer: {
+ /* Used to compute how to order the tooltips based on the tooltip value.
+ * By default, it parses the tooltip strings as numbers.
+ * If set to a falsey value, tooltips are always ordered lexicographically.
+ */
+ type: Function,
+ value: function() {
+ return function(x) {return +x;}
+ },
+ },
+ tooltips: Object,
+ highlights: Array,
+ outSelected: {
+ type: Array,
+ notify: true,
+ value: function() {
+ return [];
+ },
+ },
+ hideMissingTooltips: {
+ // If we have tooltips, but some names are missing, do we hide them?
+ type: Boolean,
+ value: true,
+ },
+ classScale: Function, // map from run name to css class
+ },
+ observers: [
+ "_initializeOutSelected(names.*)",
+ ],
+ _lookupTooltip: function(item, tooltips) {
+ return tooltips != null ? tooltips[item] : null;
+ },
+ _isNullTooltip: function(item, tooltips) {
+ if (!this.hideMissingTooltips) {
+ return true;
+ }
+ if (tooltips == null) {
+ return false;
+ }
+ return tooltips[item] == null;
+ },
+ _initializeOutSelected: function(change) {
+ this.outSelected = change.base.slice();
+ },
+ _tooltipComparator: function(tooltips, tooltipOrderer) {
+ return function(a, b) {
+ if (!tooltips || !tooltipOrderer) {
+ // if we're missing tooltips or orderer, do lexicogrpahic sort
+ return a.localeCompare(b);
+ }
+ function getValue(x) {
+ var value = tooltipOrderer(tooltips[x]);
+ return value == null || _.isNaN(value) ? -Infinity : value;
+ }
+ var aValue = getValue(a);
+ var bValue = getValue(b);
+ return aValue === bValue ? a.localeCompare(b) : bValue - aValue;
+ }
+ },
+ _checkboxChange: function(e) {
+ var name = e.srcElement.name;
+ var idx = this.outSelected.indexOf(name);
+ var checked = e.srcElement.checked;
+ if (checked && idx === -1) {
+ this.push("outSelected", name);
+ } else if (!checked && idx !== -1) {
+ this.splice("outSelected", idx, 1);
+ }
+ },
+ _isChecked: function(item, outSelectedChange) {
+ var outSelected = outSelectedChange.base;
+ return outSelected.indexOf(item) !== -1;
+ },
+ _initializeRuns: function(change) {
+ this.outSelected = change.base.slice();
+ },
+ _applyColorClass: function(item, classScale) {
+ // TODO: Update style just on the element that changes
+ // and apply at microtask timing
+ this.debounce("restyle", function (){
+ this.updateStyles();
+ }, 16);
+ return classScale(item);
+ },
+ _isHighlighted: function(item, highlights) {
+ return highlights.base.indexOf(item) !== -1;
+ },
+ });
+ </script>
+
+</dom-module>