InfoBubble not calculating div height properly in Safari - javascript

I'm trying to use a customized Info Window implementation with Google Maps API v3 called InfoBubble. As I was doing my development locally, Safari rendered the bubbles fine. However, when I uploaded it to a live server, it no longer calculated the heigh of the bubble content correctly and displays a scrollbar (which I don't want) (see http://luketilley.com/maps/).
I have done some investigating and it looks like the problem comes from this bit of code:
InfoBubble.prototype.getElementSize_ = function(element, opt_maxWidth,
opt_maxHeight) {
var sizer = document.createElement('DIV');
sizer.style['display'] = 'inline';
sizer.style['position'] = 'absolute';
sizer.style['visibility'] = 'hidden';
if (typeof element == 'string') {
sizer.innerHTML = element;
} else {
sizer.appendChild(element.cloneNode(true));
}
document.body.appendChild(sizer);
var size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight);
// If the width is bigger than the max width then set the width and size again
if (opt_maxWidth && size.width > opt_maxWidth) {
sizer.style['width'] = this.px(opt_maxWidth);
size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight);
}
// If the height is bigger than the max height then set the height and size
// again
if (opt_maxHeight && size.height > opt_maxHeight) {
sizer.style['height'] = this.px(opt_maxHeight);
size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight);
}
document.body.removeChild(sizer);
delete sizer;
return size;
};
Specifically, this line:
var size = new google.maps.Size(sizer.offsetWidth, sizer.offsetHeight);
Upon investigating what values safari reports, I confirmed that safari does indeed report different values when displaying the page locally vs. online.
Doing more testing, I also found that the issues only start when I add an image to the info bubble (check the marker off the coast of Africa).
here is the content that I'm trying to put in the info_bubble
info_content = '<div class="bubble">' +
'<h1>' + markerData.name + '</h1>' +
'<div class="icons">' +
icon_html +
'</div>' +
'<img src="' + markerData.image + '"/>' +
'<p>' + markerData.description + '</p>' +
'<p><a target="_blank" href="' + markerData.url + '"><img src="learn_more.png"/></a></p>' +
'</div>';
Any ideas on what's happening here? is there a better way to calculate the required size?
Update: This may be a bug with Safari. I just spent some time in the debugger and if I set a breakpoint and manually step through the functions, it does the right thing, but if I just let it run, it continues to misbehave. So I guess the question is now: is there a workaround?

Related

What's causing Intersection Observer API to respond differently when replacing synchronous logic with asynchronous logic?

Context
I've used the "Intersection Observer API" to build an infinite scroll image gallery. Basically this API allows me to load more items when a certain dummy DOM element enters the viewport.
Prototype
Currently the prototype is implemented for an “iPhone X” (375x812) mobile device only. See: http://urbexco-acceptance.droppages.com/min_rep_ex_working (use Chrome DevTools 'inspect' device toolbar to select the right resolution). The image gallery is generated based on 57 items in the "database". When scrolling down, first 15 elements are loaded, then 15 more elements are loaded, then another 15 elements are loaded into the DOM, then another 10 elements are loaded, and finally 2 elements are loaded. When there are still more than 15 items left to be loaded, they are added using the following logic:
function addItems(n){
// Append new items to .items-wrapper
var items = document.querySelector('.items-wrapper');
for (var i = 0; i < n; i++) {
var url = 'https://img01.ztat.net/article/spp-media-p1/09742e38c25b3e1d9716e02f8e76e87d/89fc0bda6a2c446a8e9e0d8adbc9a4fe.jpg';
width = 170.5;
height = 246;
var newDiv = document.createElement('div');
newDiv.classList.add('item');
items.appendChild(newDiv);
newDiv.innerHTML = "<img src=" + '"' + url + '"' + "width=" + '"' + width + '"' + "height=" + height + "/>";
}
}
Minimal Working Example (no mobile view possible)
https://jsfiddle.net/9jqgzymo/
Objective
Since image width and height are currently hardcoded, I am now trying to assign width and height dynamically based on the image url. I try to achieve this using the getMeta() function:
function addItems(n){
// Append new items to .items-wrapper
var items = document.querySelector('.items-wrapper');
for (var i = 0; i < n; i++) {
var url = 'https://img01.ztat.net/article/spp-media-p1/09742e38c25b3e1d9716e02f8e76e87d/89fc0bda6a2c446a8e9e0d8adbc9a4fe.jpg';
getMeta(url);
}
}
function getMeta(url){
var img = new Image();
img.onload = function(){
res = calculateAspectRatioFit(this.width, this.height, 170.5, 246)
var newDiv = document.createElement('div');
newDiv.classList.add('item');
var items = document.querySelector('.items-wrapper');
items.appendChild(newDiv);
newDiv.innerHTML = "<img src=" + '"' + url + '"' + "width=" + '"' + res.width + '"' + "height=" + res.height + "/>";
};
img.src = url;
}
function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
return { width: srcWidth*ratio, height: srcHeight*ratio };
}
Challenge
When implementing it this way, I see that - on initiation - already 30 items from the "database" where added to the DOM. Sometimes even all of them? Currently the non-working prototype is implemented for an “iPhone X” (375x812) mobile device only. See: http://urbexco-acceptance.droppages.com/min_rep_ex_not_working (use Chrome DevTools 'inspect' device toolbar to select the right resolution). For a minimal working example, see: https://jsfiddle.net/k3p20qno/
Key question
What is the reason that with my new implementation, on initiation, already 30 or more items are added to the DOM? How can I fix it?
Well the problem lies in here :
function getMeta(url){
var img = new Image();
img.onload = function(){
res = calculateAspectRatioFit(this.width, this.height, 170.5, 246)
var newDiv = document.createElement('div');
newDiv.classList.add('item');
var items = document.querySelector('.items-wrapper');
items.appendChild(newDiv);
newDiv.innerHTML = "<img src=" + '"' + url + '"' + "width=" + '"' + res.width + '"' + "height=" + res.height + "/>";
};
img.src = url;
}
Above code does an async operation with onload event. So it doesn't wait to image to be loaded.
If you turn this into a function that returns a promise you will get the result that you expect. And you should await where you call the function. That way when you add the intersection element it will add it as the last element of the items wrapper. If you don't await it will be added as the first element because the loading of the images will be async and will happen later.
function getMeta(url){
var img = new Image();
const p = new Promise(resolve =>{
img.onload = function(){
console.log( this.width+' '+ this.height );
res = calculateAspectRatioFit(this.width, this.height, 170.5, 246)
var newDiv = document.createElement('div');
newDiv.classList.add('item');
var items = document.querySelector('.items-wrapper');
items.appendChild(newDiv);
newDiv.innerHTML = "<img src=" + '"' + url + '"' + "width=" + '"' + res.width + '"' + "height=" + res.height + "/>";
resolve()
};
})
img.src = url;
return p;
}
Fiddle
Edit: Put the resolve() in the right position which is inside the load function

What is the rightway to set an openlayers popup size?

I am using the following function to set the size of a popup. However, I am noticing that always the size of the popup exceeds the size set by me and I have right margin to the left (see below).
Is there any problem with my code?
function onFeatureSelect(feature) {
selectedFeature = feature;
mydescription='' + '<div class="visual">' + feature.attributes.image + '</div>' + '<div class="textual"><h2 class="title">' + feature.attributes.title + '</h2>' +'<div class="description">' + feature.attributes.description + '</div></div>';
popup = new OpenLayers.Popup.FramedCloud("chicken",
feature.geometry.getBounds().getCenterLonLat(),
new OpenLayers.Size(500,300), mydescription , null, true, onPopupClose);
popup.autoSize = true;
popup.panMapIfOutOfView = false;
feature.popup = popup;
map.addPopup(popup);
}
Just set popup.autoSize = false; and the Popup will be 500px X 300px as

Creating elements slightly offset from the last, what am I missing?

I have a canvas called "workArea" that is much bigger than the viewport and draggable. I don't think that's relevant, but throwing it out there. I'm dynamically creating elements with knockout using the init function below. It should create each consecutive element 25 pixels to the right and down from the last one (technically the selected one, but the last created one gets selected automatically). The locy variable seems to be set and incrimenting as expected, via 25, but the locx variable gets exponentially larger each time. I must be missing something stupid.
Javascript:
ko.bindingHandlers.Item = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var $element = $(element);
var locx;
var locy;
var $pos = $('.itemView.focused').position();
var $work = $('#workArea');
if ($('.itemView.focused').length > 0) {
locx = $pos.left;
locy = $pos.top;
console.log('focused element "' + $('.itemView.focused').attr('name') + '" is at ' + locx + ',' + locy)
} else {
locx = $work.width() / 2;
locy = $work.height() / 2;
console.log('No focused elements, creating at ' + locx + ',' + locy)
}
$element.draggable({ ...draggable options here...});
locx += 25;
locy += 25;
$element.css('left', locx.toString() + 'px').css('top', locy.toString() + 'px');
console.log('Created new element at ' + locx + ',' + locy)
}
};
And here is the console log, which matches where they are showing up on the UI
No focused elements, creating at 2000,1000
Created new element at 2025,1025
focused element "SERVER01" is at 2025,1025
Created new element at 2050,1050
focused element "SERVER02" is at 2298,1050
Created new element at 2323,1075
focused element "SERVER03" is at 2819,1075
Created new element at 2844,1100
focused element "APP01" is at 3588,1100
Created new element at 3613,1125
Found the problem... had a rogue "float: left" style applied on a CSS class I forgot about.
It's working perfectly now.
I would vote to close for "too localized" but this seems like pretty odd behavior so maybe it can help someone? I won't be offended if someone does vote to close.

First a tag created in a Javascript loop not implemented

I am trying to populate a div (class='thumb") with thumnailpictures. The name of the pictures is gathered from an xml file. Every thumnail picture is encapsulated with an a-tag that points to a function to show the full picture.
On some browsers the first thumbnailpicture seems not to have this a-tag...clicking on it gives no action...
var rubriek = gup('rubriek'), // rubriek is a parameter in the url of this page pointing a specific photogallery
gallerij = rubriek + "gallery.xml",
xmlDoc = loadXMLDoc(gallerij),
x = xmlDoc.getElementsByTagName("filename"),
legebron = x[0].childNodes[0].nodeValue;
for (i = 0; i < x.length; i++) {
var beeldnummer = x[i].childNodes[0].nodeValue,
index = i + 1,
kleinbeeld = "/" + rubriek + "images/thumb/" + beeldnummer;
$('.thumb').append('<p><a class="kleintje" onclick="toonDezeFoto("' + beeldnummer + '",' + index + ',' + x.length + ');">
<img src="' + kleinbeeld + '" id="' + index + '">
</a></p>');
}
See http://www.karinedaelman.be/foto.php?rubriek=Mensen/
Found the solution: the z-index of the div that keeps the thumbnails was too low. Another div that has the site logo in it had a higher z-index and a width of 100%. Because of that the first thumbnail image was on a layer below the site logo and could not be accessed by the mouseevents....

Margins for video in webview

I am trying to embed a youtube video inside a webview and it seems there is a small margin on the right-side of the video which is not going away.
I saw many other Questions like these and tried fixing the javascript but still the margin is there.
Here is my code :
video = (WebView) v.findViewById(R.id.videoview);
// video.getSettings().setLoadWithOverviewMode(true);
// video.getSettings().setUseWideViewPort(true);
String widthAndHeight = "width='null' height='null'";
String videoURL = "http://www.youtube.com/v/DZi6DEJsOJ0";
video.setHorizontalScrollBarEnabled(false);
video.setVerticalScrollBarEnabled(false);
video.getSettings().setJavaScriptEnabled(true);
video.getSettings().setPluginsEnabled(true);
String temp = "<object "
+ widthAndHeight
+ ">"
+ "<body style='margin:0;padding:0;rightmargin:0'>"
+ "<param name='allowFullScreen' value='true'>"
+ "</param><param name='allowscriptaccess' value='always'>"
+ "</param><embed src='"
+ videoURL
+ "'"
+ " type='application/x-shockwave-flash' style='margin:0;padding:0;' allowscriptaccess='always' allowfullscreen='true'"
+ widthAndHeight + "></embed></object>";
video.loadData(temp, "text/html", "utf-8");
I tried giving the style:body=0'margin=0 tag inside the javascript . I don't know how to upload the screenshot as i am debugging on my phone but its a video with a margin of about 6pixels on the right of the video while the left hand side and the top of the video are aligned with the screen.
Well, HTML is left-aligned by default, so, in case you have a margin on the RIGHT hand side, this means that margin:0 worked. However, setting the right-hand side margin to 0 won't help as it doesn't mean the object would fill.
Try to say
+ " type='application/x-shockwave-flash' style='margin:0;width:100%;padding:0;' allowscriptaccess='always' allowfullscreen='true'"
If setting width to 100% for the embed doesn't work, perhaps try to set the width to the device screen's width, and don't forget to update on orientation.
So after much researching and trying to figure out how it works i have this working code for whoever who might need it in the future :
Display display = getActivity().getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int widthdp = (int) (width / getResources().getDisplayMetrics().density);
int height = display.getHeight();
int heightdp = (int) (height / getResources().getDisplayMetrics().density);
String widthAndHeight = "width=" + widthdp + "height=" + heightdp;
String temp = "<object "
+ widthAndHeight
+ ">"
+ "<body style='margin:0;padding:0;'>"
+ "<param name='allowFullScreen' value='true'>"
+ "</param><param name='allowscriptaccess' value='always'>"
+ "</param><embed src='"
+ videoPoP
+ "'"
+ " type='application/x-shockwave-flash' style='margin:0;padding:0;' allowscriptaccess='always' allowfullscreen='true'"
+ widthAndHeight + "></embed></object>";
video.loadData(temp, "text/html", "utf-8");
The problem was getting the width and the height for the screen would screw up the density pixels and normal pixalation problems.

Categories

Resources