| OLD | NEW |
| (Empty) |
| 1 // | |
| 2 // Copyright 2014 Google Inc. All rights reserved. | |
| 3 // | |
| 4 // Use of this source code is governed by a BSD-style | |
| 5 // license that can be found in the LICENSE file or at | |
| 6 // https://developers.google.com/open-source/licenses/bsd | |
| 7 // | |
| 8 | |
| 9 part of charted.charts; | |
| 10 | |
| 11 /// Displays tooltip for the values as user moves the mouse pointer over | |
| 12 /// values in the chart. It displays all the active values in the data row | |
| 13 /// and use the value in the dimension as the title. | |
| 14 @Deprecated('Use Hovercard') | |
| 15 class ChartTooltip implements ChartBehavior { | |
| 16 static const _TOOLTIP_OFFSET = 10; | |
| 17 final String orientation; | |
| 18 final bool showDimensionValue; | |
| 19 final bool showMeasureTotal; | |
| 20 final bool showSelectedMeasure; | |
| 21 | |
| 22 ChartArea _area; | |
| 23 ChartState _state; | |
| 24 Selection _tooltipRoot; | |
| 25 SubscriptionsDisposer _disposer = new SubscriptionsDisposer(); | |
| 26 | |
| 27 /// Constructs the tooltip. | |
| 28 /// If [showDimensionValue] is set, displays the dimension value as title. | |
| 29 /// If [showMeasureTotal] is set, displays the total value. | |
| 30 ChartTooltip({ | |
| 31 this.showSelectedMeasure: false, | |
| 32 this.showDimensionValue: false, | |
| 33 this.showMeasureTotal: false, | |
| 34 this.orientation: ORIENTATION_RIGHT}); | |
| 35 | |
| 36 /// Sets up listeners for triggering tooltip. | |
| 37 void init(ChartArea area, Selection _, Selection __) { | |
| 38 _area = area; | |
| 39 _state = area.state; | |
| 40 _disposer.addAll([ | |
| 41 area.onValueMouseOver.listen(show), | |
| 42 area.onValueMouseOut.listen(hide) | |
| 43 ]); | |
| 44 | |
| 45 // Tooltip requires host to be position: relative. | |
| 46 area.host.style.position = 'relative'; | |
| 47 | |
| 48 var _scope = new SelectionScope.element(_area.host); | |
| 49 _scope.append('div')..classed('tooltip'); | |
| 50 _tooltipRoot = _scope.select('.tooltip'); | |
| 51 } | |
| 52 | |
| 53 void dispose() { | |
| 54 _disposer.dispose(); | |
| 55 if (_tooltipRoot != null) _tooltipRoot.remove(); | |
| 56 } | |
| 57 | |
| 58 /// Displays tooltip upon receiving a hover event on an element in chart. | |
| 59 show(ChartEvent e) { | |
| 60 _tooltipRoot.first | |
| 61 ..children.clear() | |
| 62 ..attributes['dir'] = _area.config.isRTL ? 'rtl' : ''; | |
| 63 _tooltipRoot.classed('rtl', _area.config.isRTL); | |
| 64 | |
| 65 // Display dimension value if set in config. | |
| 66 if (showDimensionValue) { | |
| 67 var column = _area.config.dimensions.elementAt(0), | |
| 68 value = _area.data.rows.elementAt(e.row).elementAt(column), | |
| 69 formatter = _getFormatterForColumn(column); | |
| 70 | |
| 71 _tooltipRoot.append('div') | |
| 72 ..classed('tooltip-title') | |
| 73 ..text((formatter != null) ? formatter(value) : value.toString()); | |
| 74 } | |
| 75 | |
| 76 // Display sum of the values in active row if set in config. | |
| 77 if (showMeasureTotal) { | |
| 78 var measures = e.series.measures, | |
| 79 formatter = _getFormatterForColumn(measures.elementAt(0)), | |
| 80 row = _area.data.rows.elementAt(e.row), | |
| 81 total = 0; | |
| 82 for (int i = 0, len = measures.length; i < len; i++) { | |
| 83 total += row.elementAt(measures.elementAt(i)); | |
| 84 } | |
| 85 _tooltipRoot.append('div') | |
| 86 ..classed('tooltip-total') | |
| 87 ..text((formatter != null) ? formatter(total) : total.toString()); | |
| 88 } | |
| 89 | |
| 90 // Find the currently selectedMeasures and hoveredMeasures and show | |
| 91 // tooltip for them, if none is selected/hovered, show all. | |
| 92 var activeMeasures = []; | |
| 93 if (showSelectedMeasure) { | |
| 94 activeMeasures.addAll(_state.selection); | |
| 95 activeMeasures.add(_state.preview != null ? _state.preview : | |
| 96 _state.hovered.first); | |
| 97 if (activeMeasures.isEmpty) { | |
| 98 for (var series in _area.config.series) { | |
| 99 activeMeasures.addAll(series.measures); | |
| 100 } | |
| 101 } | |
| 102 activeMeasures.sort(); | |
| 103 } | |
| 104 | |
| 105 var data = (showSelectedMeasure) ? activeMeasures : e.series.measures; | |
| 106 | |
| 107 // Create the tooltip items base on the number of measures in the series. | |
| 108 var items = _tooltipRoot.selectAll('.tooltip-item'). | |
| 109 data(data); | |
| 110 items.enter.append('div') | |
| 111 ..classed('tooltip-item') | |
| 112 ..classedWithCallback('active', (d, i, c) => | |
| 113 !showSelectedMeasure && (d == e.column)); | |
| 114 | |
| 115 // Display the label for the currently active series. | |
| 116 var tooltipItems = _tooltipRoot.selectAll('.tooltip-item'); | |
| 117 tooltipItems.append('div') | |
| 118 ..classed('tooltip-item-label') | |
| 119 ..textWithCallback((d, i, c) => _area.data.columns. | |
| 120 elementAt((showSelectedMeasure) ? d : | |
| 121 e.series.measures.elementAt(i)).label); | |
| 122 | |
| 123 // Display the value of the currently active series | |
| 124 tooltipItems.append('div') | |
| 125 ..classed('tooltip-item-value') | |
| 126 ..styleWithCallback('color', (d, i, c) => | |
| 127 _area.theme.getColorForKey(d)) | |
| 128 ..textWithCallback((d, i, c) { | |
| 129 var formatter = _getFormatterForColumn(d), | |
| 130 value = _area.data.rows.elementAt(e.row).elementAt(d); | |
| 131 return (formatter != null) ? formatter(value) : value.toString(); | |
| 132 }); | |
| 133 | |
| 134 math.Point position = computeTooltipPosition( | |
| 135 new math.Point(e.chartX, e.chartY), | |
| 136 _tooltipRoot.first.getBoundingClientRect()); | |
| 137 | |
| 138 // Set position of the tooltip and display it. | |
| 139 _tooltipRoot | |
| 140 ..style('left', '${position.x}px') | |
| 141 ..style('top', '${position.y}px') | |
| 142 ..style('opacity', '1'); | |
| 143 } | |
| 144 | |
| 145 static String switchPositionDirection(String direction) => | |
| 146 direction == ORIENTATION_LEFT | |
| 147 ? ORIENTATION_RIGHT | |
| 148 : ORIENTATION_LEFT; | |
| 149 | |
| 150 /// Computes the ideal tooltip position based on orientation. | |
| 151 math.Point computeTooltipPosition( | |
| 152 math.Point coord, math.Rectangle rect) { | |
| 153 var x, y, direction; | |
| 154 direction = _area.config.isRTL && _area.config.switchAxesForRTL | |
| 155 ? switchPositionDirection(orientation) | |
| 156 : orientation; | |
| 157 | |
| 158 if (direction == ORIENTATION_LEFT) { | |
| 159 x = coord.x - rect.width - _TOOLTIP_OFFSET; | |
| 160 y = coord.y + _TOOLTIP_OFFSET; | |
| 161 } else { | |
| 162 x = coord.x + _TOOLTIP_OFFSET; | |
| 163 y = coord.y + _TOOLTIP_OFFSET; | |
| 164 } | |
| 165 return boundTooltipPosition( | |
| 166 new math.Rectangle(x, y, rect.width, rect.height)); | |
| 167 } | |
| 168 | |
| 169 /// Positions the tooltip to be inside of the chart boundary. | |
| 170 math.Point boundTooltipPosition(math.Rectangle rect) { | |
| 171 var hostRect = _area.host.getBoundingClientRect(); | |
| 172 | |
| 173 var top = rect.top; | |
| 174 var left = rect.left; | |
| 175 | |
| 176 // Checks top and bottom. | |
| 177 if (rect.top < 0) { | |
| 178 top += (2 * _TOOLTIP_OFFSET); | |
| 179 } else if (rect.top + rect.height > hostRect.height) { | |
| 180 top -= (rect.height + 2 * _TOOLTIP_OFFSET); | |
| 181 } | |
| 182 | |
| 183 // Checks left and right. | |
| 184 if (rect.left < 0) { | |
| 185 left += (rect.width + 2 * _TOOLTIP_OFFSET); | |
| 186 } else if (rect.left + rect.width > hostRect.width) { | |
| 187 left -= (rect.width + 2 * _TOOLTIP_OFFSET); | |
| 188 } | |
| 189 | |
| 190 return new math.Point(left, top); | |
| 191 } | |
| 192 | |
| 193 FormatFunction _getFormatterForColumn(int column) => | |
| 194 _area.data.columns.elementAt(column).formatter; | |
| 195 | |
| 196 hide(ChartEvent e) { | |
| 197 if (_tooltipRoot == null) return; | |
| 198 _tooltipRoot.style('opacity', '0'); | |
| 199 } | |
| 200 } | |
| 201 | |
| OLD | NEW |