Display tooltip on map on mouse hover

11000
7
05-15-2018 06:53 PM
SarahHulbert1
New Contributor

I want to show a tooltip with an attribute when the user hovers over an area of the map for more than a few seconds.

In this example I am trying to show the state name when a user hovers over that state.

I have implemented the tooltip but the state name is not showing up. The tooltip is blank.

I'm also unsure how to implement the delay. Currently the tooltip appears as soon as the mouse hovers over the map.

Here is the fiddle:

https://jsfiddle.net/zzz321/jfg7sqwv/2/

0 Kudos
7 Replies
KenBuja
MVP Esteemed Contributor

Have you seen this sample? Although it doesn't have the delay, it does show the tooltip as you move over features.

Also, you should get into the habit of using "on" instead of "dojo.connect".

dojo.connect(mapMain, "onMouseMove", function(evt) {
mapMain.on('mouse-move', function(evt){
RobertScheitlin__GISP
MVP Emeritus

Sarah,

   Here is a working sample for what you are looking for:

<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Tooltips</title>
  <style>
    html,
    body,
    #divMap {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #FFF;
      overflow: hidden;
      font-family: "Trebuchet MS";
    }

    #bcMain {
      width: 100%;
      height: 100%;
    }
  </style>
  <link rel="stylesheet" href="https://js.arcgis.com/3.24/dijit/themes/claro/claro.css">
  <link rel="stylesheet" href="https://js.arcgis.com/3.24/esri/css/esri.css">
  <script src="https://js.arcgis.com/3.24/"></script>
  <script>
    var lastState = null;
    require([
        "esri/map",
        "esri/layers/FeatureLayer",
        "esri/graphic",
        "esri/symbols/SimpleFillSymbol",
        "esri/symbols/SimpleLineSymbol",
        "esri/Color",
        "esri/InfoTemplate",
        "dojo/parser",
        "dojo/on",
        "dijit/layout/BorderContainer",
        "dijit/layout/ContentPane",
        "dojo/domReady!"
      ],
      function(
        Map, FeatureLayer, Graphic,
        SimpleFillSymbol, SimpleLineSymbol, Color,
        InfoTemplate, parser, on,
        BorderContainer, ContentPane) {

        parser.parse();

        var sUrlUSAService = "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/2";

        var mapMain = new Map("divMap", {
          basemap: "satellite",
          center: [-119.65, 36.87],
          zoom: 4
        });

        var infoTemplate = new InfoTemplate("<b>State Name</b>", "${state_name}");
        var lyrUSA = new FeatureLayer(sUrlUSAService, {
          mode: FeatureLayer.MODE_ONDEMAND,
          infoTemplate: infoTemplate,
          outFields: ["state_name"]
        });
        mapMain.addLayers([lyrUSA]);

        lyrUSA.on("mouse-move", function(evt) {
          if(evt.graphic.attributes["state_name"] === lastState){
            return;
          }
          setTimeout(function(){
            mapMain.infoWindow.setFeatures([evt.graphic]);
            mapMain.infoWindow.show(evt.screenPoint, mapMain.getInfoWindowAnchor(evt.screenPoint));
            lastState = evt.graphic.attributes["state_name"];
          }, 500);
        });
      });
  </script>
</head>

<body class="claro">
  <div id="bcMain" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline', liveSplitters:'true'">
    <div id="cpCenter" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">
      <div id="divMap"></div>
      </div>
    </div>
  </div>
</body>

</html>
SarahHulbert1
New Contributor

Thanks for the reply.  Unfortunately I specifically need this to work with a ArcGISDynamicMapServiceLayer not a FeatureLayer.  Is this possible?  Thanks

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Sarah,

   Your probably not aware that a ArcGISDynamicMapServiceLayer is just an image that is returned from the server and does not have access to the geometry or attributes of a feature in a layer unless a querytask is executed. So that means to get the state name for the state that the mouse is over a round trip to the server has to occur. So in your sample you would have an application that is making a hundreds or thousands of queries to the server and that would not be an application that any decent developer would ever produce. If you have to use ArcGISDynamicMapServiceLayer then you need to give up the idea of using mouseover and use mouse click instead.

0 Kudos
SarahHulbert1
New Contributor

Thanks that makes sense.  I will use mouse click.

0 Kudos
SarahHulbert1
New Contributor

I think I have a working version that uses ArcGISDynamicMapServiceLayer and only runs the query after 4 seconds.

Tooltip - JSFiddle

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Sarah,

   That works. The main thing you need now is to NOT use legacy style coding and NOT use dojo.connect.

What I mean by legacy style is esri.tasks.QueryTask in your code. In modern JS programming you should not mix legacy and AMD styles like you are doing in your code. Also as mentioned already dojo connect has been depreciated and using on is now the standard.

Here is your code cleaned to use all AMD style:

<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Tooltips</title>
  <style>
    html,
    body,
    #divMap {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
    }

    body {
      background-color: #FFF;
      overflow: hidden;
      font-family: "Trebuchet MS";
    }

    #bcMain {
      width: 100%;
      height: 100%;
    }
  </style>
  <link rel="stylesheet" href="https://js.arcgis.com/3.24/dijit/themes/claro/claro.css">
  <link rel="stylesheet" href="https://js.arcgis.com/3.24/esri/css/esri.css">
  <script src="https://js.arcgis.com/3.24/"></script>
  <script>
    var lastState = null;
    require([
      "esri/map",
      "esri/layers/ArcGISDynamicMapServiceLayer",
      "esri/graphic",
      "esri/symbols/SimpleFillSymbol",
      "esri/symbols/SimpleLineSymbol",
      "esri/Color",
      "esri/InfoTemplate",
      "dojo/parser",
      "dojo/on",
      "esri/tasks/query",
      "esri/tasks/QueryTask",
      "dojo/_base/array",
      "dijit/layout/BorderContainer",
      "dijit/layout/ContentPane",
      "dojo/domReady!"
    ],
    function(
      Map, ArcGISDynamicMapServiceLayer, Graphic,
      SimpleFillSymbol, SimpleLineSymbol, Color,
      InfoTemplate, parser, on, Query, QueryTask,
      array, BorderContainer, ContentPane) {

      parser.parse();

      var sUrlUSAService = "https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer";

      var mapMain = new Map("divMap", {
        basemap: "satellite",
        center: [-119.65, 36.87],
        zoom: 4
      });

      var infoTemplate = new InfoTemplate("<b>State Name</b>", "${state_name}");
      var lyrUSA = new ArcGISDynamicMapServiceLayer(sUrlUSAService, {
        opacity: 0.5
      });
      lyrUSA.setVisibleLayers([2]);

      mapMain.addLayers([lyrUSA]);

      queryTask = new QueryTask(sUrlUSAService + "/2");

      //build query filter
      query = new Query();
      query.returnGeometry = true;
      query.outFields = ["state_name"];

      mapMain.on("mouse-move", executeQueryTask);

      var lastMapPoint, screenPoint;

      function executeQueryTask(evt) {
        setTimeout(function() {
          if (lastMapPoint == evt.mapPoint) {
            query.geometry = evt.mapPoint;
            screenPoint = evt.screenPoint;
            //Execute task and call showResults on completion
            queryTask.execute(query, showResults);
          }
        }, 4000);
        mapMain.infoWindow.hide();
        lastMapPoint = evt.mapPoint;
      }

      function showResults(featureSet) {
        //remove all graphics on the maps graphics layer
        mapMain.graphics.clear();

        var features = featureSet.features;

        //QueryTask returns a featureSet.  Loop through features in the featureSet and add them to the map.
        array.forEach(features, function(feature) {
          var graphic = feature;

          //Set the infoTemplate.
          graphic.setInfoTemplate(infoTemplate);

          //Add graphic to the map graphics layer.
          mapMain.graphics.add(graphic);
          mapMain.infoWindow.setContent(graphic.getContent());
          mapMain.infoWindow.setTitle(graphic.getTitle());
          mapMain.infoWindow.show(screenPoint, mapMain.getInfoWindowAnchor(screenPoint));
        });
      }
    });
  </script>
</head>

<body class="claro">
  <div id="bcMain" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline', liveSplitters:'true'">
    <div id="cpCenter" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">
      <div id="divMap"></div>
    </div>
  </div>
  </div>
</body>

</html>