jQuery offset() does not work in Safari / Chrome iOS - javascript

The following code loops through an array of images and creates them based on the position of Highcharts marker ( a text that is associated with a point on a chart ). It works great in Chrome, FF, IE on desktop but does not work in Safar both Desktop or iOS and even Chrome iOS does not show the images.
The error I am getting is : main.js:453 - TypeError: 'undefined' is not an object (evaluating 'markerOffset.left')
$.each(value, function(k, v){
var z = i;
// Store the current marker
var marker = $('text').filter(function() { if($(this).html() === k) { return $(this) } });
// Get the markers offset
var markerOffset = marker.offset();
// If in Firefox, set the marker height to 13 px
if(marker.height() == 0){
markerHeight = 13;
}
else{
markerHeight = marker.height();
}
// Get the image dimensions
// Create new image object and get the width and height
// The image has to be downloaded first
var img = new Image();
// Set the image location
img.src = v.img;
// When the image is downloaded, you can get the dimensions
img.onload = function(){
var imgHeight = img.height;
var imgDivHeight = img.height;
var imgWidth = img.width;
// If the image Width is more than 90px, resize it
if(imgWidth > 50){
imgDivHeight = imgHeight / (imgWidth / 50);
imgHeight = (imgHeight / (imgWidth / 50)) + 5;
imgWidth = 50;
}
// Create the offset values based on the image sizes
**// THIS IS LINE 453**
var imgLeft = markerOffset.left - ((imgWidth - marker[0].getComputedTextLength()) / 2);
var imgTop = markerOffset.top - (imgHeight - (markerHeight / 4));
// Create an element for each value.img and make it position absolute and set the offset of the marker
$('.charts-inner').prepend('<div class="series-data series-picture-wrapper ' + hidden + ' image-on-chart" data-id="' + k + '" data-series="' + key + '" data-position-top="' + (imgTop - $('.app-ui-top').height() - (markerHeight)) + '" data-position-left="' + (imgLeft - ($('.app-ui-menu').width() + 3)) + '" data-hidden="' + hiddenAttr + '" style="z-index: ' + (5555 + z) + '; top:' + (imgTop - $('.app-ui-top').height() - (markerHeight)) + 'px; left:' + (imgLeft - ($('.app-ui-menu').width() + 3)) + 'px; width:' + imgWidth + 'px; height:' + imgDivHeight + 'px"><img src="' + v.img + '" style="width:' + imgWidth + 'px" /><div class="app-tooltip-stock nodisplay">' + v.tooltip + '</div></div>');
}
})

Right, so the problem was not the OFFSET but that $('text') is an SVG element and in Safari you cant get its content by html().
I changed the filter part to
var marker = $('text').filter(function() {
if($(this)[0].textContent === k) { return $(this) }
});
and it is working now...

Related

Modify JavaScript to access variable

I'm playing around with some code which enlarges text based on the size of the div it's in. It can be seen here:
http://codepen.io/anon/pen/zZqXXd
$(function() {
var outer = $('div'), inner = $('h1'),
difference = outer.width()-inner.width(),
ratio = outer.width()/inner.width(),
style = 'translateX(' + difference/2 + 'px) ' + 'scale(' + ratio + ')';
inner.css({'webkit-transform': style, transform: style});
});
However, I'm trying to modify it to use a variable with sizes in, not get it from the div. This was my attempt that doesn't seem to work:
$(function() {
var width = "400",
var inner = $('h1'),
difference = width -inner.width(),
ratio = width /inner.width(),
style = 'translateX(' + difference/2 + 'px) ' + 'scale(' + ratio + ')';
inner.css({'webkit-transform': style, transform: style});
});
You have to replace the comma (',') after var width = "400" with a semicolon. Your current code throws a syntax error.
The corrected code would be:
$(function() {
var width = "400"; // <-----
var inner = $('h1'),
difference = width -inner.width(),
ratio = width /inner.width(),
style = 'translateX(' + difference/2 + 'px) ' + 'scale(' + ratio + ')';
inner.css({'webkit-transform': style, transform: style});
});

Get correct click position on scaled image

This is how I get the click position when clicking on an image to do some image transformation. But my problem is, that the image has the CSS attribute max-width: 1000px. So the code works only for images which are smaller. For larger images the position result is not the real pixel which was clicked on.
My question is, if it is possible to calculate the correct click position for the natural sized image. An alternative would be to set some data attributes with the real image size like data-width: '1200px' and data-height: '1000px'. But still I have to do some calculation.
parentPosition = getPosition(event.currentTarget),
x = event.clientX - parentPosition.x,
y = event.clientY - parentPosition.y;
function getPosition(element) {
var xPosition = 0;
var yPosition = 0;
while (element) {
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
If you know natural size and current size, i think you can just do this:
naturalClickPosX = (naturalWidth / currentWidth) * currentClickPosX;
naturalClickPosY = (naturalHeight / currentHeight) * currentClickPosY;
Have a look at this JSFiddle
HTML
<img src="http://placehold.it/1200x1000" width="1000">
JavaScript
$('img').on("click", function(e){
var $img = $(this);
var currentClickPosX = e.pageX - $img.offset().left;
var currentClickPosY = e.pageY - $img.offset().top;
var currentWidth = $img.width();
var currentHeight = $img.height();
var naturalWidth = this.naturalWidth;
var naturalHeight = this.naturalHeight;
var naturalClickPosX = ((naturalWidth / currentWidth) * currentClickPosX).toFixed(0);
var naturalClickPosY = ((naturalHeight / currentHeight) * currentClickPosY).toFixed(0);
alert("Current X: " + currentClickPosX + " Current Y: " + currentClickPosY +
"\r\nNatural X: " + naturalClickPosX + " Natural Y: " + naturalClickPosY);
});
try this , will work on all sizes
$('.img-coordinate').click(function(e){
var parentOffset = $(e.target).parent().offset();
// here the X and Y on Click
X = e.pageX - $(e.target).offset().left;
Y = e.pageY - $(e.target).offset().top;
alert(X + ' , ' + Y );
});
working fiddel : https://jsfiddle.net/h09kfsoo/

Zoom image on mouse position without transform/translate

I've found a simple example about zooming a HTML image on mouse wheel. Unfortunately in my case I cannot use CSS "transform/translate" and "transformOrigin" because image's position top/left stays the same, but it has to be changed (for example, when the image becomes large enough and reaches left screen side - 'left' position must be "0", not "500px" as in my example).
My code:
<!doctype html>
<html lang="en">
<head>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript">
window.onload = function() {
scale = 1; // scale of the image
xLast = 0; // last x location on the screen
yLast = 0; // last y location on the screen
xImage = 0; // last x location on the image
yImage = 0; // last y location on the image
var mousewheelevt=(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel" //FF doesn't recognize mousewheel as of FF3.x
if (document.attachEvent) //if IE (and Opera depending on user setting)
document.attachEvent("on"+mousewheelevt, zoomImg)
else if (document.addEventListener) //WC3 browsers
document.addEventListener(mousewheelevt, zoomImg, false)
}
function zoomImg(e){
var evt = window.event || e // equalize event object
var delta = evt.detail? evt.detail*(-120) : evt.wheelDelta // check for detail first so Opera uses that instead of wheelDelta
var imgg = document.getElementById('imgg');
// find current location on screen
var xScreen = e.pageX - imgg.offsetLeft;
var yScreen = e.pageY - imgg.offsetTop;
// find current location on the image at the current scale
xImage = xImage + ((xScreen - xLast) / scale);
yImage = yImage + ((yScreen - yLast) / scale);
// determine the new scale
if (delta > 0)
{
if (scale < 5)
scale += 0.1;
}
else
{
if (scale > 1)
scale -= 0.1;
}
// determine the location on the screen at the new scale
var xNew = (xScreen - xImage) / scale;
var yNew = (yScreen - yImage) / scale;
// save the current screen location
xLast = xScreen;
yLast = yScreen;
imgg.style.transform = 'scale(' + scale + ')' + 'translate(' + xNew + 'px, ' + yNew + 'px' + ')';
imgg.style.transformOrigin = xImage + 'px ' + yImage + 'px';
}
</script>
</head>
<body>
<img id="imgg" src="http://www.baytrail.org/vtour/map4/access/CyteHils/Bayview_Tr_Grn_Hills.JPG" style="position:absolute; top:300px; left:500px;">
</body>
</html>
In my opinion all coefficients are known and I just need to replace these 2 lines to affect position, but I cannot find the right way:
imgg.style.transform = 'scale(' + scale + ')' + 'translate(' + xNew + 'px, ' + yNew + 'px' + ')';
imgg.style.transformOrigin = xImage + 'px ' + yImage + 'px';
How can I do that? If possible, please show an example with CSS "scale" and "zoom" functions.

Calculating positioning of the parent Div

Hi i want to calculate the position of the Div. Pardon me if i am not able to explain it properly but i will try to explain everything in the simplest way. I am creating sidepanel ad and to place the panels i want the position of the width. When i upload the script on my server then i get a small script which we place on the publisher website and where our script runs inside the iframe. I want to get the position of the div which has a class 'content'. Here is the screen shot.
in the above screenshot the yellow highlighted script is calculating the position of the div class="content" which is in red box. My code was working fine but on the publisher site it was not working fine and i was only able to get only two Divs whose id is like ebDiv..... (these divs are above the yellow highlighted js).
Then i found out to read the parentDiv in order to get the content positions.
i wrote this code.
var parentDoc = window;
while (parentDoc !== parentDoc.parent) {
parentDoc = parentDoc.parent;
}
parentDoc = parentDoc.document;
var parentDiv = parentDoc.getElementsByTagName('div');
var divs = [];
for (var i = 0; i < parentDiv.length; i++) {
if (parentDiv[i].className == "content") {
alert(parentDiv[i].offsetWidth);
alert(parentDiv[i].offsetLeft);
}
The width is calcuated as 1010 which is fine but i am just missing left positioning which i am getting using parentDiv[i].offsetLeft is 2.
Above the screenshot has width 1010 which is fine but left positioning is not correct.
i had this code to calculate the width.
function ReadDivPos(selector) {
var _divPos = "";
$(selector).each(function() {
var p = $(this).offset();
var w = $(this).width();
console.log("Top " + p.top) //top
console.log("left " + p.left) //left
console.log("right " + p.left + w) //right
console.log("offsetWidth " + w); //width
_divPos += "Left " + p.left + ",Width " + w + ",Avail Width " + window.screen.availWidth + ",Right " + (p.left + w) + "\\n";
});
return _divPos;
}
console.log(ReadDivPos(".content"));
when i am using the same code to calculate the positioning then it is not working .
var parentDoc = window;
while (parentDoc !== parentDoc.parent) {
parentDoc = parentDoc.parent;
}
parentDoc = parentDoc.document;
var parentDiv = parentDoc.getElementsByTagName('div');
var divs = [];
for (var i = 0; i < parentDiv.length; i++) {
if (parentDiv[i].className == "content") {
$(parentDiv[i]).each(function() {
var p = $(this).offset();
var w = $(this).width();
console.log("Top " + p.top) //top
console.log("left " + p.left) //left
console.log("right " + p.left + w) //right
console.log("offsetWidth " + w); //width
_divPos += "Left " + p.left + ",Width " + w + ",Avail Width " + window.screen.availWidth + ",Right " + (p.left + w) + "\\n";
}
}
Can someone me explain me how to fix this. Jquery/Javascript anythingwould be fine. I am not good in the frontend things so i am sorry if i could not explain it better. Thanks in advance
Here is a function used to get the position on the page of an element:
function getPosition(element) {
var xPosition = 0;
var yPosition = 0;
while (element) {
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
Used like this:
var pos = getPosition(element);
var x = pos["x"];
var y = pos["y"];
I'm not sure if this is exactly what you need, but if not maybe you can tweak it to fit your situation

Use jQuery set .css RIGHT if #foo + offset left is greater than page width

Ok, so I am trying to use jQuery to get the innerWidth() of an element #preview. I want to create a conditional that says IF x offset LEFT + #preview width is greater than page width, give it style right: z where z = #preview width + xOffset.
I apologize my code below is a mess and the syntax for .css ("right", (rightFloat + xOffset) + "px") (line 125) is off, but that's part of my problem.
<script>
$(document).ready(function(){
//append "gallery" class to all items with "popup" class
imagePreview();
$(".popup").addClass("gallery");
});
//The overlay or pop-up effect
this.imagePreview = function() { /* CONFIG */
xOffset = 40;
yOffset = 40;
// these 2 variable determine popup's distance from the cursor
// you might want to adjust to get the right result
/* END CONFIG */
$("a.preview").click(function(e) {
return false;
});
$("a.preview").hover(function(e) {
this.t = this.title;
this.title = "";
var c = (this.t != "") ? "<br/>" + this.t : "";
var rightFloat = e.pageX + ("#preview").innerWidth;
$("body").append("<p id='preview'><img src='" + this.href + "' alt='Image preview' />" + c + "</p>");
$("#preview").hide().css("top", (e.pageY - yOffset) + "px").css("left", (e.pageX + xOffset) + "px").fadeIn("2000");
while ((left + 400) > window.innerWidth) {.css("right", (rightFloat + xOffset) + "px")
}
}, function() {
this.title = this.t;
$("#preview").remove();
});
$("a.preview").mousemove(function(e) {
var top = e.pageY - yOffset;
var left = e.pageX + xOffset;
var rightFloat = e.pageX + ("#preview").innerWidth;
//flips the image if it gets too close to the right side
while ((left + 400) > window.innerWidth) {.css("right", +(rightFlaot + xOffset) + "px")
}
$("#preview").css("top", top + "px").css("left", left + "px");
});
};
</script>
Try using http://api.jquery.com/offset/
if($('#preview').offset().right<0){
var right = parseInt($(window).width()) - e.pageX + xOffset;
$("#preview").css("top", top + "px").css("right", right + "px");
}else{
var left = e.pageX + xOffset;
$("#preview").css("top", top + "px").css("left", left + "px");
}
I made these fixes because I couldn't get your code to work in jsfiddle:
var xOffset = 40;
var yOffset = 40;
$("a.preview").bind('mouseover',function(e){
var rightFloat = parseFloat(e.pageX)+$("#preview").innerWidth();
var ptop = parseFloat(e.pageY) - yOffset;
var pleft = parseFloat(e.pageX) + xOffset;
$("#preview").css({"top":ptop + "px","left":pleft + "px"});
});
There's the fixes for the top half but I have no idea what you're trying to do with the bottom part (with the while loop). Can you explain what functionality you want?

Categories