| 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 /// A behavior that draws marking lines on the chart. | |
| 12 class AxisLabelTooltip implements ChartBehavior { | |
| 13 static const _AXIS_SELECTOR = '.measure-axis-group,.dimension-axis-group'; | |
| 14 | |
| 15 SubscriptionsDisposer _disposer = new SubscriptionsDisposer(); | |
| 16 StreamSubscription _axesChangeSubscription; | |
| 17 CartesianArea _area; | |
| 18 Element _tooltipRoot; | |
| 19 | |
| 20 math.Rectangle _hostAreaRect; | |
| 21 math.Rectangle _renderAreaRect; | |
| 22 | |
| 23 void init(ChartArea area, Selection upper, Selection lower) { | |
| 24 if (area is! CartesianArea) return; | |
| 25 _area = area; | |
| 26 _axesChangeSubscription = | |
| 27 _area.onChartAxesUpdated.listen((_) => _subscribe()); | |
| 28 | |
| 29 // Axis tooltip requires host to be position: relative. | |
| 30 area.host.style.position = 'relative'; | |
| 31 } | |
| 32 | |
| 33 void dispose() { | |
| 34 _disposer.dispose(); | |
| 35 if (_tooltipRoot != null) _tooltipRoot.remove(); | |
| 36 } | |
| 37 | |
| 38 void _subscribe() { | |
| 39 var elements = _area.host.querySelectorAll(_AXIS_SELECTOR); | |
| 40 _disposer.dispose(); | |
| 41 _disposer.addAll( | |
| 42 elements.map((x) => x.onMouseOver.listen(_handleMouseOver))); | |
| 43 _disposer.addAll( | |
| 44 elements.map((x) => x.onMouseOut.listen(_handleMouseOut))); | |
| 45 } | |
| 46 | |
| 47 void _handleMouseOver(MouseEvent e) { | |
| 48 Element target = e.target; | |
| 49 if (!target.dataset.containsKey('detail')) return; | |
| 50 ensureTooltipRoot(); | |
| 51 ensureRenderAreaRect(); | |
| 52 | |
| 53 _tooltipRoot.text = target.dataset['detail']; | |
| 54 var position = computeTooltipPosition( | |
| 55 target.getBoundingClientRect(), | |
| 56 _tooltipRoot.getBoundingClientRect(), | |
| 57 _renderAreaRect); | |
| 58 | |
| 59 _tooltipRoot.style | |
| 60 ..left = '${position.x}px' | |
| 61 ..top = '${position.y}px' | |
| 62 ..opacity = '1' | |
| 63 ..visibility = 'visible'; | |
| 64 } | |
| 65 | |
| 66 void _handleMouseOut(MouseEvent e) { | |
| 67 Element target = e.target; | |
| 68 if (!target.dataset.containsKey('detail')) return; | |
| 69 if (_tooltipRoot != null) { | |
| 70 _tooltipRoot.style | |
| 71 ..opacity = '0' | |
| 72 ..visibility = 'hidden'; | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 void ensureTooltipRoot() { | |
| 77 if (_tooltipRoot == null) { | |
| 78 _tooltipRoot = new Element.tag('div') | |
| 79 ..style.position = 'absolute' | |
| 80 ..attributes['dir'] = _area.config.isRTL ? 'rtl' : '' | |
| 81 ..classes.add('chart-axis-label-tooltip'); | |
| 82 if (_area.config.isRTL) { | |
| 83 _tooltipRoot.classes.add('rtl'); | |
| 84 } else { | |
| 85 _tooltipRoot.classes.remove('rtl'); | |
| 86 } | |
| 87 _area.host.append(_tooltipRoot); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 void ensureRenderAreaRect() { | |
| 92 var layout = _area.layout; | |
| 93 _hostAreaRect = _area.host.getBoundingClientRect(); | |
| 94 _renderAreaRect = new math.Rectangle( | |
| 95 _hostAreaRect.left + layout.chartArea.x + layout.renderArea.x, | |
| 96 _hostAreaRect.top + layout.chartArea.y + layout.renderArea.y, | |
| 97 layout.renderArea.width, layout.renderArea.height); | |
| 98 } | |
| 99 | |
| 100 /// Computes the ideal tooltip position based on orientation. | |
| 101 math.Point computeTooltipPosition(math.Rectangle label, | |
| 102 math.Rectangle tooltip, math.Rectangle renderArea) { | |
| 103 var x = label.left + (label.width - tooltip.width) / 2, | |
| 104 y = label.top + (label.height - tooltip.height) / 2; | |
| 105 | |
| 106 if (x + tooltip.width > renderArea.right) { | |
| 107 x = renderArea.right - tooltip.width; | |
| 108 } else if (x < renderArea.left) { | |
| 109 x = renderArea.left; | |
| 110 } | |
| 111 | |
| 112 if (y + tooltip.height > renderArea.bottom) { | |
| 113 y = renderArea.bottom - tooltip.height; | |
| 114 } else if (y < renderArea.top) { | |
| 115 y = renderArea.top; | |
| 116 } | |
| 117 | |
| 118 return new math.Point(x - _hostAreaRect.left, y - _hostAreaRect.top); | |
| 119 } | |
| 120 } | |
| OLD | NEW |