Creating a Custom Tooltip


Level of Experience Intermediate
Requirements An embedded map and basic understanding of Underscore templates
Time Required 15 min
Source Code

 https://github.com/mapworksio/custom-tooltip

Overview

Tooltips are particularly useful in displaying feature information. Mapworks has a built-in Tooltips component which can be readily used. These can be customised or completely replaced if desired. 

Default Tooltips

To enable the default tooltip operation, set tooltipControl to true:

	var map = new Studio.core.Map("#mapworks-map", {
		apiKey: <api_key>,
		map: <map_id>,
		navigationControl: false,
		appNavigationControl: false,
		scaleControl: false,
		toolbarControl: false,
		tooltipControl: true,
		zoomControl: false
	}).load(function (err, map) {
		window.map = map;
	});

When ever you click on a feature in an active layer, it will show all visible fields associate with that feature. 

User Defined Tooltip

If you'd like, you can always create your own tooltip from scratch. 

To do this, firstly disable the default tooltip control as mentioned above. Then you'll need to pick up on the feature click events:

map.listenTo(map, "feature:mouseclick", function(ev){ YOUR CODE HERE });

The returned event is of type Studio.core.event.FeatureEvent. From this you can get the X and Y location of where was clicked to position your tooltip. 

You can also get the feature and corresponding attributes to populate your tooltip. 

Customised Template

The alternative is to use the default Mapworks tooltip controls but customise the template. This uses Underscore templatesAlso check out Studio.core.control.tooltip.Tooltip.

In the following example, we will add a button to our default template that prints out the content of our tooltip.

Step 1: Initial Setup and Tooltip Control Object

To start, we'll initialise our map and also get a reference to Studio's Underscore and jQuery.

var $ = Studio.$;
var _ = Studio._;

var map = new Studio.core.Map("#mapworks-map", {
	apiKey: "AStBVlM5TGU4ZU5USldqckxLT0RZZi8yMjk1MnRNRVQtbWRXMUJTSmk1dVBRQ8Hs8gqDcuLKaXX/99HEcW450ZLI4ZcgnIoAo50WVo/reJqlsQ",
	map: "AVIz8Sn_NkycPmrP2gMy",
	navigationControl: false,
	scaleControl: false,
	tooltipControl: true,
	zoomControl: false
}).load(function() { 
});

Once the map is ready, we will set our default view and get the tooltip control object. 

map.once('ready', function() {
	// Set the view center of the map
	map.setViewCenter(115.90798491964057, -32.01990865425378, 2327.710035750766);
	// Get the tooltip control. See Studio.core.control.tooltip.Tooltip
	var tooltipControl = map.getControl("tooltip");
 
}

Step 2: Override Tooltip Attributes and Click Template

The tooltip control object has a 'before:render' event. We can hook on to this event and update the model and template before the tooltip is rendered.

In this case we'll update the height and width of the tooltip, set our custom template, and put in a click event on our new button to trigger a print.

 map.once('ready', function() {
	// Set the view center of the map
	map.setViewCenter(115.90798491964057, -32.01990865425378, 2327.710035750766);
	// Get the tooltip control. See Studio.core.control.tooltip.Tooltip
	var tooltipControl = map.getControl("tooltip");
	/**
	 * Called before the tooltip is rendered
	 * @param model The tooltip model
	 * @param tplObj The object containing the template
	 */
	tooltipControl.on('before:render', function(model, tplObj) {
		// Add in options to the model attributes
		_.extend(model.attributes, {
			direction: "bottom", // Direction of the tooltip
			maxWidth: 350, // Maximum width of the tooltip
			maxHeight: 300 // Maximum height of the tooltip
		});
		// Override the default click template
		tplObj.clickTpl = function(e) {
			// Generate an underscore template
			var tpl = _.template(getTemplate());
			// Generate the JQuery element
			var $el = $(tpl(e));
			// Handle on-click events
			$el.on("click", "#tt-print", function() {
				var printWindow = window.open('');
				printWindow.document.write($el.find(".details").html());
				printWindow.focus();
				printWindow.print();
			});
			return $el;
		};
	});
});

Step 3: Define New Template

Lastly, we'll create the method that generates our template

// A helper function that returns an Underscore template.
// Variables in the template will be replaced by the actual model values.
var getTemplate = function() {
	var str = "";
	str += "<div id='studio-tooltip-click' class='studio-tooltip'>";
	str += "   <div class='popover popover-click <%=direction%>' style='max-width: <%=maxWidth%>px'>";
	str += "      <div class='arrow'><\/div>";
	str += "      <h3 class='popover-title popover-title-click'>";
	str += "         <span>";
	str += "            <button id='close' type='button' class='close' data-dismiss='modal'>";
	str += "            <span aria-hidden='true'>&times;<\/span><span class='sr-only'>Close<\/span>";
	str += "            <\/button>";
	str += "            <button id='tt-print' type='button'  class='close' data-dismiss='modal' title='Print Records'>";
	str += "               <span class='studio glyphicon glyphicon-print'><\/span>";
	str += "            <\/button>";
	str += "         <\/span>";
	str += "         <span id='display-name'><%=model.getDisplayName()%><\/span><br/>";
	str += "         <span id='layer-title' class='text-muted small'><%=model.getLayer().getTitle()%><\/span>";
	str += "      <\/h3>";
	str += "      <div class='details' style='max-height: <%=maxHeight%>px'>";
	str += "         <table class='table table-striped table-hover table-condensed'>";
	str += "            <tbody>";
	str += "               <%";
	str += "                  var names = _.keys(fields);";
	str += "                  var values = _.values(fields);";
	str += "                  ";
	str += "                  for(var i=0; i<names.length; i++){";
	str += "                  if(name === 'the_geom') {";
	str += "                  return;";
	str += "                  }";
	str += "                  %>";
	str += "               <tr>";
	str += "                  <td><%=names[i]%><\/td>";
	str += "                  <td><%=values[i]%><\/td>";
	str += "               <\/tr>";
	str += "               <% } %>";
	str += "            <\/tbody>";
	str += "         <\/table>";
	str += "      <\/div>";
	str += "      <%";
	str += "         var formattedArea = map.getModule('analysis').formatMeasurement(model.getArea(), true, 'm');";
	str += "         var formattedLength = map.getModule('analysis').formatMeasurement(model.getLength(), false, 'm');";
	str += "         ";
	str += "         %>";
	str += "      <div class='popover-footer'>";
	str += "         <%";
	str += "            var type = model.getType();";
	str += "            if(type !== 1) {";
	str += "            	var lengthText = 'Perimeter';";
	str += "            	if(type === 2) {";
	str += "            		lengthText = 'Length';";
	str += "            	}";
	str += "            %>";
	str += "         <table class='table no-margin table-condensed'>";
	str += "            <colgroup>";
	str += "               <col class='col-xs-4'>";
	str += "               <col class='col-xs-4'>";
	str += "            <\/colgroup>";
	str += "            <tbody>";
	str += "               <% if(type !== 2) { %>";
	str += "               <td>";
	str += "                  Area: <%=formattedArea%>";
	str += "               <\/td>";
	str += "               <% } %>";
	str += "               <td><%=lengthText%>: <%=formattedLength%><\/td>";
	str += "            <\/tbody>";
	str += "         <\/table>";
	str += "         <% } %>";
	str += "      <\/div>";
	str += "   <\/div>";
	str += "<\/div>";
	return str;
}

That's it! See the result in action below:

See the Pen Creating a Custom Tooltip 2 by Mapworks (@mapworks) on CodePen.

Next: Mapworks What3Words Integration