I have the following Google Map test: http://jsfiddle.net/gM6Z6/
As you can see it gets your position and then shows it on the map using three markers.
What I want to do is when a user hovers over any of the three markers, I want to show the following tooltip NEXT to the marker avatar:
var tooltipOptions={
marker:marker,
content: "You're here!",
cssClass:'tooltip'
};
var tooltip = new Tooltip(tooltipOptions);
I'm not sure how to best do this, as I need this to work for all three markers, and be in the same position regardless of which marker was hovered. It should ALWAYS appear next to the avatar like in the foursquare screenshot below BUT should move to the left or right dependant on the position of the icon on screen to allow it to fit.
Can anyone help? As the docs are a little vague for my liking on this... I can create the tooltip but I'm confused how best to show it for all three markers but in the same position and viewport aware.
Here you go:
http://jsfiddle.net/nickaknudson/KVa2d/
tooltip = new Tooltip("text");
...
tooltip.open(map, marker);
Customizable via CSS.
UPDATE
Commented code:
http://jsfiddle.net/nickaknudson/KVa2d/12/
UPDATE 2
Removed unnecessary bits:
http://jsfiddle.net/nickaknudson/KVa2d/14/
//========================
// Tooltip Class Definition
// extends OverlayView:
// https://developers.google.com/maps/documentation/javascript/reference#OverlayView
//========================
var Tooltip
Tooltip = function(tip) {
this.tip = tip;
this.buildDOM();
};
$.extend(Tooltip.prototype, google.maps.OverlayView.prototype, {
// build the DOM
buildDOM: function() {
// Body DIV
this.bdiv = $("<div></div>").addClass('WindowBody').html(this.tip);
// Window DIV
this.wdiv = $("<div></div>").addClass('Window').append(this.bdiv);
// Shadow DIV
this.sdiv = $("<div></div>").addClass('WindowShadow');
// Start Closed
this.close();
},
// API - onAdd
onAdd: function() {
$(this.getPanes().floatPane).append(this.wdiv);
$(this.getPanes().floatShadow).append(this.sdiv);
},
// API - onRemove
onRemove: function() {
this.wdiv.detach();
this.sdiv.detach();
},
// API - draw
draw: function() {
var pos, left, top;
// projection is accessible?
if (!this.getProjection()) return;
// position is accessible?
if (!this.get('position')) return;
// convert projection
pos = this.getProjection().fromLatLngToDivPixel(this.get('position'));
// top offset
top = pos.y - this.getAnchorHeight() / 2;
// left offset
if (this.getMap().getCenter().lng() > this.get('position').lng()) {
left = pos.x + this.wdiv.width() * 0.5;
} else {
left = pos.x - this.wdiv.width() * 1.5;
}
// window position
this.wdiv.css('top', top);
this.wdiv.css('left', left);
// shadow position
this.sdiv.css('top', (top - this.getAnchorHeight() / 2));
this.sdiv.css('left', left);
// shadow size
this.sdiv.width(this.wdiv.width());
this.sdiv.height(this.wdiv.height());
},
// open Tooltip
open: function(map, anchor) {
// bind to map
if (map) this.setMap(map);
// bind to anchor
if (anchor) {
this.set('anchor', anchor);
this.bindTo('anchorPoint', anchor);
this.bindTo('position', anchor);
}
// need to force redraw otherwise it will decide to draw after we show the Tooltip
this.draw();
// show tooltip
this.wdiv.show();
this.sdiv.show();
// set property
this.isOpen = true;
},
// close Tooltip
close: function() {
// hide tooltip
this.wdiv.hide();
this.sdiv.hide();
// set property
this.isOpen = false;
},
// correctly get the anchorPoint height
getAnchorHeight: function() {
// See: https://developers.google.com/maps/documentation/javascript/reference#InfoWindow
// "The anchorPoint is the offset from the anchor's position to the tip of the InfoWindow."
return -1 * this.get('anchorPoint').y;
}
});
UPDATE 3
Better positioning using outerWidth() and outerHeight() to take borders etc into account. Removed shadow div.
http://jsfiddle.net/nickaknudson/KVa2d/16/
//========================
// Tooltip Class Definition
// extends OverlayView:
// https://developers.google.com/maps/documentation/javascript/reference#OverlayView
//========================
var Tooltip
Tooltip = function(tip) {
this.tip = tip;
this.buildDOM();
};
$.extend(Tooltip.prototype, google.maps.OverlayView.prototype, {
// build the DOM
buildDOM: function() {
// Window DIV
this.wdiv = $("<div></div>").addClass('Window').append(this.tip);
// Start Closed
this.close();
},
// API - onAdd
onAdd: function() {
$(this.getPanes().floatPane).append(this.wdiv);
},
// API - onRemove
onRemove: function() {
this.wdiv.detach();
},
// API - draw
draw: function() {
var pos, left, top;
// projection is accessible?
if (!this.getProjection()) return;
// position is accessible?
if (!this.get('position')) return;
// convert projection
pos = this.getProjection().fromLatLngToDivPixel(this.get('position'));
// top offset
top = pos.y - this.getAnchorHeight() / 2 - this.wdiv.outerHeight()/2;
// left offset
if (this.getMap().getCenter().lng() > this.get('position').lng()) {
left = pos.x + this.wdiv.outerWidth() * 0.3;
} else {
left = pos.x - this.wdiv.outerWidth() * 1.3;
}
// window position
this.wdiv.css('top', top);
this.wdiv.css('left', left);
},
// open Tooltip
open: function(map, anchor) {
// bind to map
if (map) this.setMap(map);
// bind to anchor
if (anchor) {
this.set('anchor', anchor);
this.bindTo('anchorPoint', anchor);
this.bindTo('position', anchor);
}
// need to force redraw otherwise it will decide to draw after we show the Tooltip
this.draw();
// show tooltip
this.wdiv.show();
// set property
this.isOpen = true;
},
// close Tooltip
close: function() {
// hide tooltip
this.wdiv.hide();
// set property
this.isOpen = false;
},
// correctly get the anchorPoint height
getAnchorHeight: function() {
// See: https://developers.google.com/maps/documentation/javascript/reference#InfoWindow
// "The anchorPoint is the offset from the anchor's position to the tip of the InfoWindow."
return -1 * this.get('anchorPoint').y;
}
});
RESOURCES
modified from my GoogleMapsiPhoneWindow
You can use the mouseover event to display your tooltip. (See events doc here). You only need to show it for marker2 since it has the highest zIndex value.
google.maps.event.addListener(marker2, 'mouseout', function() {
});
Here's a jsFiddle displaying a tooltip using InfoWindow. You don't have the tooltip code in your example. Can you update your example using the tooltip you created?
Related
I use a Zoom JavaScript for zoom my images when I click on it.
This JavaScript creates a hidden copy of my image with bigger dimensions.
Problem is, when I load my page, the body takes a height and width according to the hidden image.
You can see at the right of the screen the menu doesn't fit with the width of the screen (the hidden image is not displayed).
Is there a solution when I load the page, the size of the body does not take into account the hidden image?
// To achieve this effect we're creating a copy of the image and scaling it up. Next we'll pull the x and y coordinates of the mouse on the original image. Then we translate the big image so that the points we are looking at match up. Finally we create a mask to display the piece of the image that we're interested in.
let settings = {
'magnification': 3,
'maskSize': 200
}
// Once our images have loaded let's create the zoom
window.addEventListener("load", () => {
// find all the images
let images = document.querySelectorAll('.image-zoom-available');
// querySelectorAll produces an array of images that we pull out one by one and create a Zoombini for
Array.prototype.forEach.call(images, (image) => {
new Zoombini(image);
});
});
// A Zoombini (or whatever you want to call it), is a class that takes an image input and adds the zoomable functionality to it. Let's take a look inside at what it does.
class Zoombini {
// When we create a new Zoombini we run this function; it's called the constructor and you can see it taking our image in from above
constructor(targetImage) {
// We don't want the Zoombini to forget about it's image, so let's save that info
this.image = targetImage;
// The Zoombini isActive after it has opened up
this.isActive = false;
// But as it hasn't been used yet it's maskSize will be 0
this.maskSize = 0;
// And we have to start it's coordinates somewhere, they may as well be (0,0)
this.mousex = this.mousey = 0;
// Now we're set up let's build the necessary compoonents
// First let's clone our original image, I'm going to call it imageZoom and save it our Zoombini
this.imageZoom = this.image.cloneNode();
// And pop it next to the image target
this.image.parentNode.insertBefore(this.imageZoom, this.image);
// Make the zoom image that we'll crop float above it's original sibling
this.imageZoom.style.zIndex = 1;
// We don't want to be able to touch it though, we want to reach whats underneat
this.imageZoom.style.pointerEvents = "none";
// And so we can translate it let's make it absolute
this.imageZoom.style.position = "absolute";
// Now let's scale up our enlarged image and add an event listener so that it resizes whenever the size of the window changes
this.resizeImageZoom();
window.addEventListener("resize", this.resizeImageZoom.bind(this), false);
// Now that we're finishing the constructor we need to addeventlisteners so we can interact with it
// This function is just below, but still exists within our Zoombini
this.UI();
// Finally we'll apply an initial mask at default settings to hide this image
this.drawMask();
}
// resizeImageZoom resizes the enlarged image
resizeImageZoom() {
// So let's scale up this version
this.imageZoom.style.width = this.image.getBoundingClientRect().width * settings.magnification + 'px';
this.imageZoom.style.height = "unset"
}
// This could be inside the constructor but it's nicer on it's own I think
UI() {
this.image.addEventListener('mousemove', (event) => {
// When we move our mouse the x and y coordinates from the event
// We subtract the left and top coordinates so that we get the (x,y) coordinates of the actualy image, where (0,0) would be the top left
this.mousex = event.clientX - this.image.getBoundingClientRect().left;
this.mousey = event.clientY - this.image.getBoundingClientRect().top;
// if we're not active then don't display anything
if (!this.isActive) return;
// The drawMask() function below displays our the portion of the image that we're interested in
this.drawMask();
});
// When they mousedown we open up our mask
this.image.addEventListener('mousedown', () => {
// But it can be opening or closing, so let's pass in that information
this.isExpanding = true;
// To do that we start the maskSizer function, which calls itself until it reaches full size
this.maskSizer();
// And hide our cursor (we know where it is)
this.image.classList.add('is-active');
});
// if the mouse is released, close the mask
this.image.addEventListener('mouseup', () => {
// if it's not expanding, it's closing
this.isExpanding = false;
// if the mask has already expanded we'll need to start another maskSizer to shrink it. We don't run the maskSizer unless the mask is changing
if (this.isActive) this.maskSizer();
});
// same as above, caused by us moving out of the zoom area
this.image.addEventListener('mouseout', () => {
this.isExpanding = false;
if (this.isActive) this.maskSizer();
});
}
// The drawmask function shows us the piece of the image that we are hovering over
drawMask() {
// Let's use getBoundingClientRect to get the location of our images
let image = this.image.getBoundingClientRect();
let imageZoom = this.imageZoom.getBoundingClientRect();
// We'll start by getting the (x,y) of our big image that matches the piece we're mousing over (which we stored from our event listener as this.mousex and this.mousey). This is a clunky bit of code to help the zooms work in a variety of situations.
let prop_x = this.mousex / image.width * imageZoom.width * (1 - 1 / settings.magnification) - image.x - window.scrollX;
let prop_y = this.mousey / image.height * imageZoom.height * (1 - 1 / settings.magnification) - image.y - window.scrollY;
// Shift the large image by that amount
this.imageZoom.style.left = -prop_x + "px";
this.imageZoom.style.top = -prop_y + "px";
// Now we need to create our mask
// First let's get the coordinates of the point we're hovering over
let x = this.mousex * settings.magnification;
let y = this.mousey * settings.magnification;
// And create and apply our clip
let clippy = "circle(" + this.maskSize + "px at " + x + "px " + y + "px)";
this.imageZoom.style.clipPath = clippy;
this.imageZoom.style.webkitClipPath = clippy;
}
// We'll use the maskSizer to either expand or shrink the size of our mask
maskSizer() {
// We're in maskSizer so we're changing the size of our mask. Let's make the mask radius larger if the Zoombini is expanding, or shrink it if it's closing. The numbers below might need to be adjusted. It closes faster than it opens
this.maskSize = this.isExpanding ? this.maskSize + 35 : this.maskSize - 40;
// It has the form of: condition ? value-if-true : value-if-false
// Think of the ? as "then" and : as "else"
// if we've reaached max size, don't make it any larger
if (this.maskSize >= settings.maskSize) {
this.maskSize = settings.maskSize;
// we'll no longer need to change the maskSize so we'll just set this.isActive to true and let our mousemove do the drawing
this.isActive = true;
} else if (this.maskSize < 0) {
// Our mask is closed
this.maskSize = 0;
this.isActive = false;
this.image.classList.remove('is-active');
} else {
// Or else we haven't reached a size that we want to keep yet. So let's loop it on the next available frame
// We bind(this) here because so that the function remains in context
requestAnimationFrame(this.maskSizer.bind(this));
}
// After we have the appropriate size, draw the mask
this.drawMask();
}
}
function zoom(e) {
var zoomer = e.currentTarget;
e.offsetX ? offsetX = e.offsetX : offsetX = e.touches[0].pageX
e.offsetY ? offsetY = e.offsetY : offsetX = e.touches[0].pageX
x = offsetX / zoomer.offsetWidth * 100
y = offsetY / zoomer.offsetHeight * 100
zoomer.style.backgroundPosition = x + '% ' + y + '%';
}
//My image generated after page load
.image-zoom-available {
height: unset;
border-radius: 30px;
z-index: 1;
pointer-events: none;
position: absolute;
width: 834.688px;
left: 526.646px;
top: 231.729px;
clip-path: circle(0px at 439.062px 987.812px);
}
<div class="col-12 col-xl-3 col-lg-5 justify-content-center ">
<div class="mb-3">
<img class="image-zoom-available" style="height:75%; border-radius: 30px" src='{{ asset(' /radio/ ') }}{{examen.idpatient.id}}_examen_{{examen.id}}_radio.png' id="image_radio" draggable="false" />
</div>
</div>
Try adding the following property in your hidden image css :
display: none
A non visible element still take space in the web page. Cf: What is the difference between visibility:hidden and display:none?
Remove or override the display: none property when you want to display the image.
I add
this.imageZoom.style.display = "none";
on the event : mouseup and
this.imageZoom.style.display = "block";
on mousedown event. And it's fix thanks !
This is the fiddle. https://jsfiddle.net/igor_g/ksjkpg0t/16/
My intention is to build a scrollbar on a strip of colors. The colors are taken from the text it is supposed to scroll. Basically, the strip is an overview of all the colors that are used in the text fonts. The text is generated dynamically and can be very large and very small. My intention is to make the scroller's size proportional and at the same time scroll properly. I have tried various combinations using jquery but I just can not seem to get the scroller to work the way I want. Sometimes, the scroller doesnt seem to point to the right text passage. How can this be fixed?
The jquery code is as follows:
/// here is our plugin declaration
(function ( $ ) {
$.fn.colorScroller = function( options ) {
var settings = $.extend({
replaceBlack: 'rgb(83, 84, 72)',
colorScrollClass: "color-map",
overlayClass: "overlay",
scrollSectionClass: "mapSection",
coloredTextClass: "passage"
}, options );
// assign this(the selector that is calling this function) to container
var container = this;
// getting the height of container
var containerHeight = container.outerHeight(true);
// creating overlay scrolling element
var $overlay = $('<div class="'+settings.overlayClass+'" ></div>')
//creating container for colored parts
var $colorScroll=$('<div class="'+settings.colorScrollClass+'" ></div>')
// appending colormap element after container in DOM
container.after($colorScroll);
// approximate total height of browser vertical scroll buttons
var browserScrollButtons = 26;
// setting height of colorscroll element to the height of container
$colorScroll.outerHeight(container.outerHeight()-browserScrollButtons );
var scrollerHandleMin = 31
// here we are calculating the total height of text elements of container
var totalHeight = 0;
container.children('.'+ settings.coloredTextClass).each(function(){
totalHeight = totalHeight + $(this).outerHeight(true);
});
// calculate height of text empty elements like br or <p></p>
var emptyHeight = 0;
container.children().not('.'+ settings.coloredTextClass).each(function(){
emptyHeight = emptyHeight + $(this).outerHeight(true);
});
// here we are calculating the ratio b/n total height of children of container and the height of color-scroll element
var ratio = totalHeight/$colorScroll.outerHeight();
// here we create a jquery object containing of small divs which will be colored, and associated with each passage div in container
var $mini = $('.'+settings.coloredTextClass, container).map(function(){
// getting the height of passage, setting the height of small div element by dividing by ratio
var heightPassage=$(this).outerHeight(true)/ratio+'px';
// getting the color of passage
var colorPassage=$(this).css('color');
// color change if color is black
if (colorPassage=='rgb(0, 0, 0)')
colorPassage = settings.replaceBlack;
var elem = $('<div class="'+settings.scrollSectionClass+'" style="height:'+heightPassage+'; background-color:'+colorPassage+'" ></div>').get(0)
// returning a jquery object element with class, height and color associated according to previous calculations
return elem
});
// get approximate height of browser scroll bar handle
var browserScrollBarHeight = (containerHeight*(containerHeight-browserScrollButtons ))/(totalHeight + emptyHeight )
browserScrollBarHeight = browserScrollBarHeight > scrollerHandleMin ? browserScrollBarHeight : scrollerHandleMin
// set overlay scroller height to browser scroll handle height
$overlay.outerHeight(browserScrollBarHeight);
var overlayHeight = $overlay.outerHeight();
// appending the minified elements into colorscroll element
$($mini).appendTo($colorScroll);
// appending overlay element into color-scroll element
$colorScroll.append($overlay);
// getting top position of container related to document top
var colorScrollTop = $colorScroll.offset().top+1+parseInt($colorScroll.css('margin-top').replace('px', ''))
// getting multiple to create algorithm for converting top positions
var k = (totalHeight + emptyHeight - containerHeight)/($colorScroll.innerHeight()-overlayHeight)
// attaching draggable to overlay scrolling element, so that it can be moved along color scroll element
$overlay.draggable({
// constrain movement to color-scroll element only
containment: "."+settings.colorScrollClass,
// what to do when overlay is dragged
drag: function() {
// getting top position of overlay related to document top
var top = $(this).offset().top;
container.animate({
// scroll container vertically to the point of overlay top (related to color-scroll element ) associated with text in container
scrollTop: (top-colorScrollTop)*k +'px'
}, 2)
},
});
/// when mouse on color-scroller unbind container scroll and enble draggable
/// when mouse leaves color-scroller bind container scroll and disable draggable
$colorScroll
.mouseenter(function() {
$overlay.draggable('enable')
container.off('scroll', scrollText)
})
.mouseleave(function() {
$overlay.draggable('disable')
container.on('scroll', scrollText)
});
// function triggered when container scrolled, basically scroll the overlay
function scrollText(){
$overlay.animate({
top: container.scrollTop()/k + 'px'
}, 1)
}
container.on('scroll', scrollText)
// when the color-scroll element is clicked
$colorScroll.on('click',function(e){
// calculate the position of click related to color-scroll itself
var topPosition = e.pageY-$(this).offset().top;
// and move overlay top to that position
$overlay.animate({
top: topPosition+'px'
}, 200)
// and scroll container to text associated with overlay top
container.animate({
scrollTop: (topPosition+overlayHeight)*ratio-containerHeight+'px'
}, 10)
})
return container;
};
}( jQuery ));
/// end plugin
$(document).ready(function() {
var passes = [0, 1, 2, 3, 4, 5, 6]
for (var i in passes) {
col = document.getElementById('pass' + i).style.color;
var element = document.createElement("section");
element.style.background = col;
document.getElementById("left").appendChild(element);
}
canvas = document.createElement("canvas");
canvas.id = 'canvas';
canvas.style = 'height:700px;width:50px;';
/// here we init plugin function
$('#document_content').colorScroller({replaceBlack: 'rgb(0,0,0)'});
/// the other option with defaults are :
// colorScrollClass: "color-map", css class of colored scrollbar
// overlayClass: "overlay", css class of the custom scrollbar
// scrollSectionClass: "mapSection", css class of the small colored sections in colored scroll bar
// coloredTextClass: "passage" css class of the original text part
///
});
I currently have this setting: tooltip: { isHtml: true, trigger: 'both' }. When I just mouse over a point, I have some other code that repositions the tooltip that appears. The problem is however that when I click on the tooltip and then mouse over another point, a secondary tooltip appears that overlaps the first. What I want is for the user to have to click off the first tooltip before being able to see any others.
Also, is it possible for the user to not have to click on the point for the selection to be removed? So the user could click somewhere on the screen or on another point and the tooltips would then either disappear or correctly display the new tooltip.
Code that shifts the tooltip
//Start of shifting code
google.visualization.events.addOneTimeListener(chart, 'ready', function () {
var container = document.querySelector('#chart_div > div:last-child');
function setPosition(e) {
if (e && e.target) {
var tooltip = $(e.target);
setTimeout(function () {
tooltip.css('left', 635 + 'px');
tooltip.css('top', 100 + 'px');
}, 1);
}
else {
var tooltip = container.querySelector('.google-visualization-tooltip');
tooltip.style.left = 635 + 'px';
tooltip.style.top = 100 + 'px';
}
}
if (typeof MutationObserver === 'function') {
var observer = new MutationObserver(function (m) {
for (var i = 0; i < m.length; i++) {
if (m[i].addedNodes.length) {
setPosition();
break; // once we find the added node, we shouldn't need to look any further
}
}
});
observer.observe(container, {
childList: true
});
}
else if (document.addEventListener) {
container.addEventListener('DOMNodeInserted', setPosition);
}
else {
container.attachEvent('onDOMNodeInserted', setPosition);
}
});
//End of shifting code
An image of what is happening
There is no way in the API to suppress spawning tooltips on mouseover when a tooltip spawned by a selection is present. You can turn off tooltips entirely, however, and implement your own custom tooltips with the requisite logic to control when you spawn one (which, since you would have complete control of the tooltip's construction, would also allow you to remove the MutationObserver that watches for new tooltips to adjust positioning). You can use the "select" and "onmouseover"/"onmouseout" events to spawn and remove tooltips.
If you implement custom tooltips, you can use any logic you want to remove them. If you choose not to implement custom tooltips, you can remove tooltips spawned on select by clearing the chart's selection via the setSelection method:
chart.setSelection(); // set the selection to null, which clears all selected points and tooltips
You can call that from whatever event handler you like (as long as the chart object is within scope of the event handler).
I have following code for image zoom in/out. The issue is when I try to position image according to my need i.e. I apply margin left to image or image container i.e. #view it effects image zoom (in/out) – upon image zooming image starts moving to the left (because of margin) as you can see in the fiddle link below. Removing margin left makes this again run fine. I want to place it to my wish place without having effect on zoom. Please let me know if I am not clear.
jsfiddle
/*style.css*/
#view {
border: 1px solid #333333 ;
overflow: hidden ;
position: relative ;
width: 400px ;
/*giving margin left to move image to the center*/
margin-left: 400px;
}
.imageZoomInOut {
display: block ;
left: 0px ;
top: 0px ;
}
#zoom {
background-imageZoomInOut: url( "./white_fade.png" ) ;
border: 1px solid #000000 ;
cursor: pointer ;
display: none ;
height: 200px ;
position: absolute ;
width: 200px ;
z-index: 100 ;
}
//******************** js *******************
// When the WINDOW is ready, initialize. We are going with
// the window load rather than the document so that we
// know our imageZoomInOut will be ready as well (complete with
// gettable dimentions).
$(document).ready(function(){
// First, let's get refernces to the elements we will
// be using.
var view = $( "#view" );
var imageZoomInOut = $( ".imageZoomInOut" );
// Create the ZOOM element - this will be added with
// Javascript since it's more of an "effect".
var zoom = $( "<a id='zoom'><span><br /></span></a>" );
// Before we start messing with the scripts, let's
// update the display to allow for the absolute
// positioning of the imageZoomInOut and zoomer.
// Set an explicit height / width on the view based
// on the initial size of the imageZoomInOut.
view.width( imageZoomInOut.width() );
view.height( imageZoomInOut.height() );
// Now that the view has an explicit width and height,
// we can change the displays for positioning.
imageZoomInOut.css( "position", "absolute" );
// Set an exlicit height on the imageZoomInOut (to make sure
// that some of the later calcualtions don't get
// messed up - I saw some irradic caculated-height
// behavior).
imageZoomInOut.height( imageZoomInOut.height() );
// Before we add the zoom square, we need it to match
// the aspect ratio of the imageZoomInOut.
zoom.width( Math.floor( imageZoomInOut.width() / 2 ) );
zoom.height( Math.floor( imageZoomInOut.height() / 2 ) );
// Now, add the zoom square to the view.
view.append( zoom );
// ---------------------------------------------- //
// ---------------------------------------------- //
// Now that we have our UI set up physically, we need
// to bind the event handlers.
// We want to show and hide the zoom only when the
// user hovers over the view.
view.hover(
function( event ){
// Show the soom.
zoom.show();
},
function( event ){
// Hide the zoom.
zoom.hide();
}
);
// As the user mouses over the view, we can get the
// mouse coordinates in terms of the page; we need
// to be able to translate those into VIEW-based
// X and Y cooridates. As such, let's get the offset
// of the view as our base 0x0 coordinate.
//
// NOTE: We are doing this here so that we do it once,
// rather than every time the mouse moves.
viewOffset = view.offset();
// Get the jQuery-ed version of the window as we will
// need to access it's scroll offsets every time the
// mouse moves over the div.
//
// NOTE: This will change the change the refernce to
// "window" for all of the code in this closure.
var window = $( window );
// As the user moves across the view, we want to move
// the zoom square with them.
view.mousemove(
function( event ){
// Get the window scroll top; the mouse
// position is relative to the window, NOT
// the document.
var windowScrollTop = window.scrollTop();
var windowScrollLeft = window.scrollLeft();
// Translate the mouse X / Y into view-local
// coordinates that can be used to position
// the zoom box.
setZoomPosition(
Math.floor(
event.clientX - viewOffset.left + windowScrollLeft
),
Math.floor(
event.clientY - viewOffset.top + windowScrollTop
)
);
}
);
// I position the zoom box within the view based on
// the given view-local mouse coordinates.
var setZoomPosition = function( mouseLeft, mouseTop ){
// Ideally, we want to keep the zoom box centered
// on the mouse. As such, we want the given mouse
// left and mouse top coordiantes to be in the
// middle of the zoom box.
var zoomLeft = (mouseLeft - (zoom.width() / 2));
var zoomTop = (mouseTop - (zoom.height() / 2))
// As we move the zoom box around, however, we
// never want it to go out of bounds of the view.
// Protect the top-left bounds.
zoomLeft = Math.max( zoomLeft, 0 );
zoomTop = Math.max( zoomTop, 0 );
// Protect the bottom-right bounds. Because the
// bottom and right need to take the dimensions
// of the zoom box into account, be sure to use
// the outer width to include the border.
zoomLeft = Math.min(
zoomLeft,
(view.width() - zoom.outerWidth())
);
zoomTop = Math.min(
zoomTop,
(view.height() - zoom.outerHeight())
);
// Position the zoom box in the bounds of the
// imageZoomInOut view box.
zoom.css({
left: (zoomLeft + "px"),
top: (zoomTop + "px")
});
};
// Now that we have the mouse movements being tracked
// properly, we need to track the click on the zoom to
// zoom in the imageZoomInOut on demand. To do that, however,
// we need to start storing some information with the
// imageZoomInOut so we can manipulate it as needed.
imageZoomInOut.data({
zoomFactor: (view.width() / zoom.width()),
zoom: 1,
top: 0,
left: 0,
width: imageZoomInOut.width(),
height: imageZoomInOut.height(),
originalWidth: imageZoomInOut.width(),
originalHeight: imageZoomInOut.height()
});
// Now, let's attach the click event handler to the
// zoom box.
zoom.click(
function( event ){
// First, prevent the default since this is
// not a navigational link.
event.preventDefault();
// Let's pass the position of the zoom box
// off to the function that is responsible
// for zooming the imageZoomInOut.
zoomImage(
zoom.position().left,
zoom.position().top
);
}
);
// I take the zoom box coordinates and translate them
// into an actual imageZoomInOut zoom based on the existing
// zoom and offset of the imageZoomInOut.
//
// NOTE: We don't care about the dimensions of the
// zoom box itself as those should have already been
// properly translated into the zoom *factor*.
var zoomImage = function( zoomLeft, zoomTop ){
// Get a reference to the imageZoomInOut data object so we
// don't need to keep retreiving it.
var imageZoomInOutData = imageZoomInOut.data();
// Check to see if we have reached the max zoom
// or if the imageZoomInOut is currently animating.
// If so, just return out.
if (
(imageZoomInOutData.zoom == 5) ||
(imageZoomInOut.is( ":animated" ))
){
// Zooming in beyond this is pointless (and
// can cause the browser to mis-render the
// imageZoomInOut).
return;
}
// Scale the imageZoomInOut up based on the zoom factor.
imageZoomInOutData.width =
(imageZoomInOut.width() * imageZoomInOutData.zoomFactor);
imageZoomInOutData.height =
(imageZoomInOut.height() * imageZoomInOutData.zoomFactor);
// Change the offset set data to re-position the
// 0,0 coordinate back up in the top left.
imageZoomInOutData.left =
((imageZoomInOutData.left - zoomLeft) * imageZoomInOutData.zoomFactor);
imageZoomInOutData.top =
((imageZoomInOutData.top - zoomTop) * imageZoomInOutData.zoomFactor);
// Increase the zoom.
imageZoomInOutData.zoom++;
// Animate the zoom.
imageZoomInOut.animate(
{
width: imageZoomInOutData.width,
height: imageZoomInOutData.height,
left: imageZoomInOutData.left,
top: imageZoomInOutData.top
},
500
);
};
// I reset the imageZoomInOut zoom.
var resetZoom = function(){
// Get a reference to the imageZoomInOut data object so we
// don't need to keep retreiving it.
var imageZoomInOutData = imageZoomInOut.data();
// Reset the imageZoomInOut data.
imageZoomInOutData.zoom = 1;
imageZoomInOutData.top = 0;
imageZoomInOutData.left = 0;
imageZoomInOutData.width = imageZoomInOutData.originalWidth;
imageZoomInOutData.height = imageZoomInOutData.originalHeight;
// Animate the zoom.
imageZoomInOut.animate(
{
width: imageZoomInOutData.width,
height: imageZoomInOutData.height,
left: imageZoomInOutData.left,
top: imageZoomInOutData.top
},
300
);
};
$("button").click(function(){
resetZoom();
});
// As a final step, to make sure that the imageZoomInOut can
// be zoomed out, bind the mousedown to the document.
$( document ).mousedown(
function( event ){
// Check to see if the view is in the event
// bubble chain for the mouse down. If it is,
// then this click was in the view or its
// child elements.
var closestView = $( event.target ).closest( "#view" );
// Check to see if this mouse down was in the
// imageZoomInOut view.
if (!closestView.size()){
// The view was not found in the chain.
// This was clicked outside of the view.
// Reset the imageZoomInOut zoom.
resetZoom();
}
}
);
});
<!--- html --->
<div id="view">
<img class="imageZoomInOut" height="600" width="400" src="http://imedia.tv.com.pk/tvb/galery_celebrities/medium/Fawad_afzal_khan_image_90.jpg">
</div>
Try to change the padding to
left: 400px;
Tell me if this works for you
EXAMPLE
It looks like it keeps adding a new newHeight and a newDistance each time i click, I am trying to save original height with a global var at the top and using data to do that but i get weird results, basically i should be able to reset newDistance and newHeight to first original values as per before to run the lot with a click but it doesn't and i get new added values each time i click breaking my layout as a result:
talents = $(".talenti");
filter = $(".filtra");
genHeight = $("#container").data($("#container").height());
filter.click(function(e) {
e.preventDefault();
if (talents.hasClass("opened")) {
$(".nasco").slideToggle();
$("#wrapNav").slideToggle("10", "linear");
talents.removeClass('opened');
filter.addClass('opened');
$("#container").css("height", genHeight);
} else {
filter.addClass('opened');
};
if (filter.hasClass("opened")) {
$("#wrapNav").slideToggle("10", "linear", function(){
$("#sliding-navigation").slideToggle();
var newHeight = $("#container").height() + $("#wrapNav").outerHeight(true);
var newDistance = newHeight - $("#container").height() + 22;
$("#container").animate({height: newHeight}, 50,function(){
$(".box").animate({top: newDistance});
});
});
}
});
talents.click(function(e) {
e.preventDefault();
if (filter.hasClass("opened")) {
$("#sliding-navigation").slideToggle();
$("#wrapNav").slideToggle("10", "linear");
filter.removeClass('opened');
talents.addClass('opened');
$("#container").css("height", genHeight);
} else {
talens.addClass('opened');
};
if (talents.hasClass("opened")) {
$("#wrapNav").slideToggle("10", "linear", function(){
$(".nasco").slideToggle();
var newHeight = $("#container").height() + $("#wrapNav").outerHeight(true);
var newDistance = newHeight - $("#container").height() + 156;
$("#container").animate({height: newHeight}, 50,function(){
$(".box").animate({top: newDistance});
});
});
}
});
Anyone?
So, based on the code I could download about 20min ago from your test site, I managed to get it working with the following code:
$(document).ready(function(){
// placeholder to contain the original height...
var original_height = 0;
talents = $(".talenti");
filter = $(".filtra");
filter.click(function(e){
e.preventDefault();
if (filter.hasClass('opened')){
filter.removeClass('opened');
// toggle the wrapping, just with a zero top coordinate...
$("#wrapNav").slideToggle("10", "linear", function(){
$("#sliding-navigation").hide();
$(".box").animate({top: '0px'});
});
// reset to the original height...
$("#container").height(original_height);
}
else {
// get the original height if it's not already set...
if (original_height == 0)
original_height = $("#container").height();
filter.addClass('opened');
if (talents.hasClass("opened"))
{
$(".nasco").hide();
$("#wrapNav").slideToggle();
talents.removeClass('opened');
}
// toggle the wrapping with a height of the nav as top coordinate...
$("#wrapNav").slideToggle("10", "linear", function(){
$("#sliding-navigation").slideToggle(true, function(){
// need the height of the nav before we know how far to move the boxes...
var newHeight = $("#wrapNav").outerHeight(true);
$(".box").animate({top: newHeight});
// set the container's new height, much like you had...
$("#container").height(original_height + newHeight);
});
});
}
});
talents.click(function(e) {
e.preventDefault();
if (talents.hasClass('opened')) {
talents.removeClass('opened');
// toggle the wrapping, just with a zero top coordinate...
$("#wrapNav").slideToggle("10", "linear", function(){
$(".nasco").hide();
$(".box").animate({top: '0px'});
});
// reset to the original height...
$("#container").height(original_height);
}
else {
// get the original height if it's not already set...
if (original_height == 0)
original_height = $("#container").height();
talents.addClass('opened');
if (filter.hasClass("opened"))
{
$("#sliding-navigation").hide();
$("#wrapNav").slideToggle();
filter.removeClass('opened');
}
// toggle the wrapping with a height of the nav as top coordinate...
$("#wrapNav").slideToggle("10", "linear", function(){
// need the height of the nav before we know how far to move the boxes...
$(".nasco").slideToggle(true, function(){
var newHeight = $("#wrapNav").outerHeight(true);
$(".box").animate({top: newHeight});
// set the container's new height, much like you had...
$("#container").height(original_height + newHeight);
});
});
}
});
});
A few points adding food for thought:
I simplified the multiple if statements to make it easier to understand and process
I used hide() to avoid messy animation problems if you clicked on FILTER multiple times in a row
I only adjusted the top coordinates of the boxes to achieve this
I would have preferred to contain the boxes in a more general container, allowing for easier animation and management, but I understand that wordpress doesn't always give you the most room to work, so this should get you on your way!
It might not be completely what you're looking for in your animation, but it's a working example of the code you had and should get you 90% of the way...hope this helps! :)
What about using the data collection of the container element rather than a global variable i.e. at the top record the height
$("#container").data('height', $("#container").height());
then to use
$("#container").data('height');
i.e. to reset the height
$("#container").css({height: $("#container").data('height') });
I feel a bit suspicious about how the global variable is working. Worth a try maybe