This is not a new problem, but I have yet to come up with a very satisfactory solution. How do you keep your infoTemplate from getting cut off? My content isn't very complicated. I have used a map.infoWindow.resize to make it a little wider. I have a function to format the contents.
map.infoWindow.resize(340,300);
I have a listener on the show event of the map.infoWindow. The trick apparently isn't to move your infoTemplate, but instead to move your map if it detects the window is going to get cut off, panning the map enough so the tag isn't cropped.
on(map.infoWindow, "show", adjustMapExtent);
I got this from an older thread and it seems to be working.
function adjustMapExtent(){ var maxPoint = new Point(map.extent.xmax, map.extent.ymax, spatialReference); var centerPoint = new Point(map.extent.getCenter()); var mapPt = new Point(map.infoWindow.location, spatialReference); screenPt = map.toScreen(mapPt); //Convert these to screen coordinates var maxPointScreen = map.toScreen(maxPoint); var centerPointScreen = map.toScreen(centerPoint); //Subtract the size of the infoWindow, including a buffer. //This will show whether the infoWindow would spill out of the current view. var xDiff = Math.abs(maxPointScreen.x - screenPt.x) - 350; var yDiff = Math.abs(maxPointScreen.y - screenPt.y) - 310; //If required, recalculate a new centerpoint which accounts for the infoWindow if (xDiff < 0) { centerPointScreen.x -= xDiff; } if ( yDiff < 0) { centerPointScreen.y += yDiff; } //Pan the map to the new centerpoint (in Map coordinates) centerPoint = map.toMap(centerPointScreen, spatialReference); map.centerAt(centerPoint); }
Here's my problem/complaint. This works the first time. However, unless you've dismissed the tag, the 'show' listener doesn't get fired again, because there is still an infoWindow displayed. The event doesn't fire for every new infoWindow, just 'when an infoWindow in visible'. This is an important distinction.
Is there some other event I could be listening for? I tried adding an event listener on the map click to do a 'map.infoWindow.hide()', but that seems to prevent the info tag from ever displaying.
I've had similar problems, and the solution I've come up with is to revise the _setPosition method of the Popup "class". It ensures the popup always opens "towards" the center of the map (i.e. where it will have the most space). The full popup is guaranteed to be visible if (1) the popup width inlcuding the pointer is less than half the width of the map and (2) the popup height inlcuding the pointer is less than half the height of the map.
The trick is to execute the code below before any popups are instantiated. However, if the only popup in the application is the map's, you could replace
Popup.prototype._setPosition = function(screenPoint) {
with
map.infoWindow._setPosition = function(screenPoint) {
(assuming "map" is a reference to your map object).
As I'm preparing this post, the code below looks kind of garbled, and not nicely formatted like in the source file, so hopefully it comes out ok. If not, I've also attached the text file containing it.
require(["dojo/dom-geometry", "dojo/dom-style", "esri/kernel", "esri/dijit/Popup"], function(domGeom, domStyle, esriNS, Popup) {
/** modified to open popup with best possible placement (towards center of screen) **/ Popup.prototype._setPosition = function(screenPoint) { domStyle.set(this.domNode, { left: screenPoint.x + "px", top: screenPoint.y + "px", right: null, bottom: null });
var mapBox = domGeom.position(this.map.container, true); var horizontalPosition = ""; var verticalPosition = "";
if (screenPoint.x < (mapBox.w * 0.33)) horizontalPosition = "Left"; else if (screenPoint.x > (mapBox.w * 0.67)) horizontalPosition = "Right";
if (screenPoint.y < (mapBox.h * 0.33)) verticalPosition = "top"; else if (screenPoint.y > (mapBox.h * 0.67)) verticalPosition = "bottom"; else if (horizontalPosition == "") { horizontalPosition = ((screenPoint.x < (mapBox.w * 0.5)) ? "Left" : "Right"); /*verticalPosition = ((screenPoint.y < (mapBox.h * 0.5)) ? "top" : "bottom");*/ }
var anchorText = verticalPosition + horizontalPosition; var offsetX = ((this.offsetX) ? this.offsetX : 0); var offsetY = ((this.offsetY) ? this.offsetY : 0); var positionerHeight = 0; var positionerWidth = 0;
switch (anchorText) { case "top": case "bottom": positionerHeight = 14; break;
case "Left": case "Right": positionerWidth = 13; break;
default: var esriVersion = esriNS.version.toString().split("."); esriVersion[0] = parseInt(esriVersion[0], 10); esriVersion[1] = parseInt(esriVersion[1], 10);
if ((esriVersion[0] > 3) || ((esriVersion[0] == 3) && (esriVersion[1] >= 8))) { positionerHeight = 14; positionerWidth = -16; } else positionerHeight = 45;
break; }
var positionerBox = domGeom.getContentBox(this._positioner); var positionerStyle = { left: null, right: null, top: null, bottom: null };
if (horizontalPosition == "") positionerStyle.left = (positionerBox.w * -0.5) + "px"; else positionerStyle[horizontalPosition.toLowerCase()] = (positionerWidth + offsetX) + "px";
if (verticalPosition == "") positionerStyle.top = (positionerBox.h * -0.5) + "px"; else positionerStyle[verticalPosition] = (positionerHeight + offsetY) + "px";
domStyle.set(this._positioner, positionerStyle); this._showPointer(anchorText); }; });
I don't want to hijack Tracy's thread but this has frustrated me as well so I was watching this thread. I want/need to implement this into a legacy 3.3 API project but it's choking on my dojo.require. I tried "esri.kernel" instead of "esri/kernel" but it can't find it.
Any guesses on how to reference this under legacy coding?
"esri/kernel" was introduced at version 3.8. You might want to try what's mentioned in the help of using "esri.version".
When coding legacy (non-AMD) style, there is no need to require the module. All methods and properties are available in the namespace. For example,
esri.version
.
I get what you're saying, but I'm not any good with separating things into modules OR how to create my own variation of what ESRI has written. All the examples I've found to get me started makes some assumptions about what background and programming experience you come from (which I don't have). I get lost right away with how to get everything talking to each other.