From 9229a38ef36c7f663f9eb5329afb34d179d61852 Mon Sep 17 00:00:00 2001 From: Andrew Harvey Date: Sat, 23 Jul 2016 20:13:12 +1000 Subject: [PATCH] add popup offset option closes #1962 --- js/ui/popup.js | 56 ++++++++++- test/manual/marker.png | Bin 0 -> 2653 bytes test/manual/popup-offset-multiple-fixed.html | 100 +++++++++++++++++++ test/manual/popup-offset-radius.html | 97 ++++++++++++++++++ 4 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 test/manual/marker.png create mode 100644 test/manual/popup-offset-multiple-fixed.html create mode 100644 test/manual/popup-offset-radius.html diff --git a/js/ui/popup.js b/js/ui/popup.js index 46bd8d55254..773c543a30e 100644 --- a/js/ui/popup.js +++ b/js/ui/popup.js @@ -6,6 +6,7 @@ var util = require('../util/util'); var Evented = require('../util/evented'); var DOM = require('../util/dom'); var LngLat = require('../geo/lng_lat'); +var Point = require('point-geometry'); /** * A popup component. @@ -16,10 +17,19 @@ var LngLat = require('../geo/lng_lat'); * top right corner of the popup. * @param {boolean} [options.closeOnClick=true] If `true`, the popup will closed when the * map is clicked. - * @param {string} options.anchor - A string indicating the popup's location relative to + * @param {string} [options.anchor] - A string indicating the popup's location relative to * the coordinate set via [Popup#setLngLat](#Popup#setLngLat). * Options are `'top'`, `'bottom'`, `'left'`, `'right'`, `'top-left'`, - * `'top-right'`, `'bottom-left'`, and `'bottom-right'`. + * `'top-right'`, `'bottom-left'`, and `'bottom-right'`. If unset the anchor will be + * dynamically set to ensure the popup falls within the map container with a preference + * for `'bottom'`. + * @param {number|PointLike|Object} [options.offset] - The offset in pixels to apply + * from the geographical location of the popup. This can be a single number representing + * the radius of circular offsets, [`PointLike`](#PointLike) for a fixed `[x,y]` offset + * regardless of the anchor, or an Object mapping anchor to a [`PointLike`](#PointLike) + * objects to apply a different offsets for each anchor, eg. `{top: [0,-10], bottom: [0,0]}`. + * For the offset values represented by a [`PointLike`](#PointLike), negatives indicate + * left and up. * @example * var popup = new mapboxgl.Popup() * .setLngLat(e.lngLat) @@ -187,15 +197,48 @@ Popup.prototype = util.inherit(Evented, /** @lends Popup.prototype */{ } var pos = this._map.project(this._lngLat).round(), - anchor = this.options.anchor; + anchor = this.options.anchor, + offset = this.options.offset; + + // a fixed offset regardless of the anchor + var offsetFixed = [0, 0]; + // an object of offsets per each anchor + var offsets; + + if (offset) { + if (typeof offset === 'number') { + // when offset is a fixed radius + var cornerOffset = Math.round(Math.sqrt(0.5 * Math.pow(offset, 2))); + offsets = { + 'top': [0, offset], + 'top-left': [cornerOffset, cornerOffset], + 'top-right': [-cornerOffset, cornerOffset], + 'bottom': [0, -offset], + 'bottom-left': [cornerOffset, -cornerOffset], + 'bottom-right': [-cornerOffset, -cornerOffset], + 'left': [offset, 0], + 'right': [-offset, 0] + }; + } else if (offset.length && offset.length === 2) { + // when the offset is a fixed [x,y] + offsetFixed = offset; + } else { + // when the offset is preset for each anchor + offsets = offset; + } + } + + // maximum offsets for each anchor configuration: top, bottom + var offsetTop = (offsets && offsets.top || offsetFixed)[1]; + var offsetBottom = (offsets && offsets.bottom || offsetFixed)[1]; if (!anchor) { var width = this._container.offsetWidth, height = this._container.offsetHeight; - if (pos.y < height) { + if (pos.y + offsetBottom < height) { anchor = ['top']; - } else if (pos.y > this._map.transform.height - height) { + } else if (pos.y + offsetTop > this._map.transform.height - height) { anchor = ['bottom']; } else { anchor = []; @@ -214,6 +257,9 @@ Popup.prototype = util.inherit(Evented, /** @lends Popup.prototype */{ } } + // apply the offset to the Popup pos + pos = pos._add(Point.convert(offsets && offsets[anchor] || offsetFixed)); + var anchorTranslate = { 'top': 'translate(-50%,0)', 'top-left': 'translate(0,0)', diff --git a/test/manual/marker.png b/test/manual/marker.png new file mode 100644 index 0000000000000000000000000000000000000000..2ff92111b70fef6167270ddcb728ff5f4481af8f GIT binary patch literal 2653 zcmV-j3ZnIiP)bRu`N_7 zfl?@Lx!5SQDr(h=7Ye8d2nMP6frpAHTnd$nNX0`b6~t8v32xdF8rwhsV@N9%>W#56 zF}HB>`nGt%rw?bxjED7ocFvgilUD4^&d&Vj+jGWe&Ybyip$0FI1*8C};eQi>5x{U@ zRCv1vpc!ZZ>H&ZF^%+nOG}#(8;Ii>p^MLOFIY1^ba)A450?s4F{R1c);Qk!JBw!P8 z5fD*+{TKK(@bzdGC|WgaHn0I$26(#LFexbspU=nS$&-nXkH_ov;`Mp~Xl!hxv9Xar zAV5t`4Sv6$`uh5wj@<^l3%rf|p)AE}VY7iZf$sw`<_}|IW0^H;7CAXNWM^lSnVCsK zLPDPoP+woqg$oxbFE6LGw3N%2FB1xdB5nE%_$#mzxYXy8M48dRTR0pB(56xfg(o$xREE>rx*g$G)=5pwMtZ0R@x@YOhrY7Sh;eg&@{~~?J2S) z46|F74=6PSBWBE)Ax@k)p-hyS)2C01S+izEs%>Y0$#%&~M|K`N0`Pb|V*B>(qP4YE zwWAkkZEY2Wg@wZ7@tCFE0A7u@tZd+OdB6mN z!ALdjBOq=d!hU1i;oP}%#iK`$RF~B<0)arJbK1`S%31=1^c^K7C5f9iZ>lb%<J ziU|`Y7=?v^MSYd!1^%b+#O-#AlP6EAE?d+%apHuzpXR5J*Pfl4;?}KORhKF1Y~H-N z-%T?OIhrW|F@5^K zbm>ynu`44lFV85f1xVH$=zTCJto3I~U*z1IExp_Pu3JMBr4bF)a6cpfg zyY)pE@ESZ9maTu1k&%JV=d(9D2a=kaN?KZ)aa9gTVZ(qq9cyzeAAB6NyW_y!{VXnLB!y$+)tfN{rHa6NGkkg4I?5@64S663yKu+i8&6~!>`x^2w z6af5wzwH4z9g~x)PQq$xYG`O^ustZJ($LUgZgtffavlKyp-_m*%1YYz#@Hg`|dkEj@jg5^J)z#IiZ$2x-@Ar$?*jVG8@3(YG#!K-(>u=iH+Bk6FfW^Pr z;9=jseYCZ;8CSjA)wcg4Y&AYUUewputNyWV=l1Q}V$`Tn=Bel%XeMF5)!zgH0rv0T zKhPg*(6M{>ZgVf;?e4aBA!n)xKzP00s60jMRIXjSCcIv+dDc#kk9p@Cz991Q@>G|@ zHkK?|VwBa6eA>8Iyl0el^ypF5Wr;dRjvO&hJO4{>WdVExnUzEUV(i$lqN=J&b(x}u z-|rXW$B#G4Y79H*6Wfi(v$L}Y^%HDe@#M)9F>l^HbL}eZt1OUtCr%l6w07-U)#bCC zHEY(GW&IPG0H9wa0=32+78Mn#E~91a*s;Sbs}7jhUs*Z}kT*&M$TSNF4jfQj)&a9` z-#&Aih9>0HRZI9WhDQNoVq(P3ojX;Rx!>&FyVsly?*ds-1Mn>C>l$&*wAC3Ic1QElXz^@W2>=$Kw&JSFaX#@7`7Ir-OU< z?um8l)`_^dIJ2xTP>{Ij72tv?5HV@eBys4_ArT6Nl!*$3LgL`TgCZ#@$t+4BZ)Ut= zw=A6z!0#}f*8nkX+BC6i*DlfA+-#euU@#~SA3iK*&YT%Z)Kg$TGAX5UUPJzJF9hoI z`NWnjTf~(sSE45B^5x57)22;g%9JUQLjpF0uNlQy3 zB_)N_)Krp_lNmE+3~_OBosvcdgFzlYeoReG4OLZDR99DX_3Bjufk1aLd;uHuChu?pWJP&pE-4Ag{cfm@ABa<~+eeQZ6>zcUZ z@M3LV>T|q=HOou_a^lNCWnBlpW^?Sym`N9Dn0xtZLgDqGD%Q|{VLwq2uOld?@3Q`= zBvOYk9@Ds553l>ke%+UvpVNC`ZzzhyeR8GIOyDEp5v;LcHj>Y*8d(UZiom>qVsfwr*t#SJ%q&A z#rV78SYE(MO;YDQ!}|}EMKOqYmFG3A+oZEYNMewaav$Kp7U0BGD9@0ivW>_;0FJ_m z!a$z*pQ#Qa5>6H7M<&j898MM%R2@VlUid#C9YQ + + + Mapbox GL JS debug page + + + + + + + + +
+ + + + diff --git a/test/manual/popup-offset-radius.html b/test/manual/popup-offset-radius.html new file mode 100644 index 00000000000..67db027bad8 --- /dev/null +++ b/test/manual/popup-offset-radius.html @@ -0,0 +1,97 @@ + + + + Mapbox GL JS debug page + + + + + + + + +
+ + + +