[AngularJS] Tooltip


Tooltip via AngularJS. For tooltip written in Go and compiled to JavaScript via GopherJS, see [2].

Demo

Real world application of tooltip is Pāli Tipiṭaka.

Source code:

index.html | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!doctype html>
<html ng-app="demoTooltip">
<head>
  <meta charset="utf-8">
  <title>AngularJS Tooltip Demo</title>
  <link rel="stylesheet" type="text/css" href="tooltip.css">
</head>
<body>

<div id="container">
  <span>Manopubbaṅgamā</span> <span>dhammā</span>, <span>manoseṭṭhā</span>
  <span>manomayā</span>; <span>Manasā</span> <span>ce</span>
  <span>paduṭṭhena</span>, <span>bhāsati</span> <span></span>
  <span>karoti</span> <span></span>; <span>Tato</span> <span>naṃ</span>
  <span>dukkhamanveti</span>, <span>cakkaṃva</span> <span>vahato</span>
  <span>padaṃ</span>.
</div>

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="tooltip.js"></script>
<script src="app.js"></script>
</body>
</html>
app.js | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
'use strict';


angular.module('demoTooltip', ['tooltip']).
  run(['AddTooltipToElement',
  function(AddTooltipToElement) {

    var spans = document.getElementById("container").querySelectorAll("span");
    for (var i=0; i < spans.length; i++) {
      AddTooltipToElement.add(spans[i]);
    }

  }]);
tooltip.js | repository | view raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
'use strict';

/* Services */


angular.module('tooltip', []).
  factory('tooltip', ['$rootScope', '$compile', function($rootScope, $compile) {
    // init tooltip
    var scope = $rootScope.$new(true);
    var isMouseInTooltip = false;
    scope.onmouseenter = function() {
      // mouse enters tooltip
      isMouseInTooltip = true;
    };
    scope.onmouseleave = function() {
      // mouse leaves tooltip
      isMouseInTooltip = false;
      hide();
    };
    var _left = 0;
    var _top = 0;

    var tooltip = $compile('<div class="tooltip" ng-mouseenter="onmouseenter()" ng-mouseleave="onmouseleave()"></div>')(scope);
    tooltip.css('max-width', viewWidth() + 'px');

    // append tooltip to the end of body element
    angular.element(document.getElementsByTagName('body')[0]).append(tooltip);


    function viewWidth() {
      // FIXME: why -32 here?
      return (window.innerWidth || document.documentElement.clientWidth) - 32;
    }

    function setContent(content) {
      tooltip.children().remove();
      if (angular.isUndefined(content)) {
        throw 'In tooltip: content undefined!';
      } else if (angular.isString(content)) {
        tooltip.html(content);
      } else {
        tooltip.append(content);
      }
    }

    function setPosition(position) {
      _left = parseInt(position.left.replace('px', ''));
      _top = parseInt(position.top.replace('px', ''));
    }

    function show() {
      // move tooltip to the right
      // (don't cross the right side of browser inner window)
      var _right = _left + tooltip.prop('offsetWidth');
      if ( _right > viewWidth() )
        _left -= (_right - viewWidth());

      tooltip.css('left', _left + 'px');
      tooltip.css('top', _top + 'px');
    }

    function hide() {
      if (!isMouseInTooltip)
        tooltip.css('left', '-9999px');
    }

    var serviceInstance = {
      viewWidth: viewWidth,
      isHidden: function() {return (tooltip.css('left') === '-9999px');},
      getLeftSpace: function() {return _left;},
      getRightSpace: function() {return viewWidth() - _left - tooltip.prop('offsetWidth');},
      setContent: setContent,
      setPosition: setPosition,
      show: show,
      hide: hide
    };
    return serviceInstance;
  }]).

  factory('AddTooltipToElement', ['tooltip', function(tooltip) {
    // when user's mouse hovers over words,
    // delay a period of time before look up.
    var DELAY_INTERVAL = 1000; // ms

    var isMouseInWord = false;

    function onWordMouseOver(e) {
      isMouseInWord = true;
      this.style.color = 'red';

      setTimeout(angular.bind(this, function() {
        // 'this' keyword here refers to raw dom element
        if (this.style.color === 'red') {
          // mouse is still on word
          var word = this.innerHTML.toLowerCase();
          tooltip.setContent(
            word + ' ' + word + '<br>' +
            '<span>' + word + '</span>' + ' ' + word
          );
          tooltip.setPosition({
            'left': (this.getBoundingClientRect().left + 'px'),
            'top': (this.getBoundingClientRect().top + this.offsetHeight + 'px'),
          });
          tooltip.show();
        }
      }), DELAY_INTERVAL);
    }

    function onWordMouseOut(e) {
      isMouseInWord = false;
      this.style.color = '';

      setTimeout(angular.bind(this, function() {
        if (!isMouseInWord) {
          tooltip.hide();
        }
      }), DELAY_INTERVAL);
    }

    function add(elm) {
      elm.onmouseover = onWordMouseOver;
      elm.onmouseout = onWordMouseOut;
    }

    var serviceInstance = { add: add };
    return serviceInstance;
  }]);
tooltip.css | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/**
 * keyword: css long word force line break
 * http://webdesignerwall.com/tutorials/word-wrap-force-text-to-wrap
 */
.tooltip {
  position: absolute;
  left: -9999px;
  background-color: #CCFFFF;
  border-radius: 10px;
  font-family: Tahoma, Arial, serif;
  word-wrap: break-word;
}

Tested on: Chromium Version 50.0.2661.102 Ubuntu 16.04 (64-bit), AngularJS 1.5.5.


References:

[1]
[2]GitHub - siongui/gopherjs-tooltip: Tooltip in Go. Compiled to JavaScript via GopherJS