Catch browser's "zoom" event in JavaScript - javascript
Is it possible to detect, using JavaScript, when the user changes the zoom in a page?
I simply want to catch a "zoom" event and respond to it (similar to window.onresize event).
Thanks.
There's no way to actively detect if there's a zoom. I found a good entry here on how you can attempt to implement it.
I’ve found two ways of detecting the
zoom level. One way to detect zoom
level changes relies on the fact that
percentage values are not zoomed. A
percentage value is relative to the
viewport width, and thus unaffected by
page zoom. If you insert two elements,
one with a position in percentages,
and one with the same position in
pixels, they’ll move apart when the
page is zoomed. Find the ratio between
the positions of both elements and
you’ve got the zoom level. See test
case.
http://web.archive.org/web/20080723161031/http://novemberborn.net/javascript/page-zoom-ff3
You could also do it using the tools of the above post. The problem is you're more or less making educated guesses on whether or not the page has zoomed. This will work better in some browsers than other.
There's no way to tell if the page is zoomed if they load your page while zoomed.
Lets define px_ratio as below:
px ratio = ratio of physical pixel to css px.
if any one zoom The Page, the viewport pxes (px is different from pixel ) reduces and should be fit to The screen so the ratio (physical pixel / CSS_px ) must get bigger.
but in window Resizing, screen size reduces as well as pxes. so the ratio will maintain.
zooming: trigger windows.resize event --> and change px_ratio
but
resizing: trigger windows.resize event --> doesn’t change px_ratio
//for zoom detection
px_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
$(window).resize(function(){isZooming();});
function isZooming(){
var newPx_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
if(newPx_ratio != px_ratio){
px_ratio = newPx_ratio;
console.log("zooming");
return true;
}else{
console.log("just resizing");
return false;
}
}
The key point is difference between CSS PX and Physical Pixel.
https://gist.github.com/abilogos/66aba96bb0fb27ab3ed4a13245817d1e
Good news everyone some people! Newer browsers will trigger a window resize event when the zoom is changed.
I'm using this piece of JavaScript to react to Zoom "events".
It polls the window width.
(As somewhat suggested on this page (which Ian Elliott linked to): http://novemberborn.net/javascript/page-zoom-ff3 [archive])
Tested with Chrome, Firefox 3.6 and Opera, not IE.
Regards, Magnus
var zoomListeners = [];
(function(){
// Poll the pixel width of the window; invoke zoom listeners
// if the width has been changed.
var lastWidth = 0;
function pollZoomFireEvent() {
var widthNow = jQuery(window).width();
if (lastWidth == widthNow) return;
lastWidth = widthNow;
// Length changed, user must have zoomed, invoke listeners.
for (i = zoomListeners.length - 1; i >= 0; --i) {
zoomListeners[i]();
}
}
setInterval(pollZoomFireEvent, 100);
})();
This works for me:
var deviceXDPI = screen.deviceXDPI;
setInterval(function(){
if(screen.deviceXDPI != deviceXDPI){
deviceXDPI = screen.deviceXDPI;
... there was a resize ...
}
}, 500);
It's only needed on IE8. All the other browsers naturally generate a resize event.
There is a nifty plugin built from yonran that can do the detection. Here is his previously answered question on StackOverflow. It works for most of the browsers. Application is as simple as this:
window.onresize = function onresize() {
var r = DetectZoom.ratios();
zoomLevel.innerHTML =
"Zoom level: " + r.zoom +
(r.zoom !== r.devicePxPerCssPx
? "; device to CSS pixel ratio: " + r.devicePxPerCssPx
: "");
}
Demo
Although this is a 9 yr old question, the problem persists!
I have been detecting resize while excluding zoom in a project, so I edited my code to make it work to detect both resize and zoom exclusive from one another. It works most of the time, so if most is good enough for your project, then this should be helpful! It detects zooming 100% of the time in what I've tested so far. The only issue is that if the user gets crazy (ie. spastically resizing the window) or the window lags it may fire as a zoom instead of a window resize.
It works by detecting a change in window.outerWidth or window.outerHeight as window resizing while detecting a change in window.innerWidth or window.innerHeight independent from window resizing as a zoom.
//init object to store window properties
var windowSize = {
w: window.outerWidth,
h: window.outerHeight,
iw: window.innerWidth,
ih: window.innerHeight
};
window.addEventListener("resize", function() {
//if window resizes
if (window.outerWidth !== windowSize.w || window.outerHeight !== windowSize.h) {
windowSize.w = window.outerWidth; // update object with current window properties
windowSize.h = window.outerHeight;
windowSize.iw = window.innerWidth;
windowSize.ih = window.innerHeight;
console.log("you're resizing"); //output
}
//if the window doesn't resize but the content inside does by + or - 5%
else if (window.innerWidth + window.innerWidth * .05 < windowSize.iw ||
window.innerWidth - window.innerWidth * .05 > windowSize.iw) {
console.log("you're zooming")
windowSize.iw = window.innerWidth;
}
}, false);
Note: My solution is like KajMagnus's, but this has worked better for me.
⬤ The resize event works on modern browsers by attaching the event on window, and then reading values of thebody, or other element with for example (.getBoundingClientRect()).
In some earlier browsers it was possible to register resize event
handlers on any HTML element. It is still possible to set onresize
attributes or use addEventListener() to set a handler on any element.
However, resize events are only fired on the window object (i.e.
returned by document.defaultView). Only handlers registered on the
window object will receive resize events.
⚠️ Do resize your tab, or zoom, to trigger this snippet:
window.addEventListener("resize", getSizes, false)
function getSizes(){
let body = document.body
body.width = window.innerWidth
body.height = window.innerHeight
console.log(body.width +"px x "+ body.height + "px")
}
getSizes()
⬤ An other modern alternative: the ResizeObserver API
Depending your layout, you can watch for resizing on a particular element.
This works well on «responsive» layouts, because the container box get resized when zooming.
function watchBoxchange(e){
info.textContent = e[0].contentBoxSize[0].inlineSize+" x "+e[0].contentBoxSize[0].blockSize + "px"
}
new ResizeObserver(watchBoxchange).observe(fluid)
#fluid {
width: 200px;
height:100px;
overflow: auto;
resize: both;
border: 3px black solid;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 8vh
}
<div id="fluid">
<info id="info"></info>
</div>
💡 Be careful to not overload javascript tasks from user gestures events. Use requestAnimationFrame whenever you needs redraws.
I'd like to suggest an improvement to previous solution with tracking changes to window width. Instead of keeping your own array of event listeners you can use existing javascript event system and trigger your own event upon width change, and bind event handlers to it.
$(window).bind('myZoomEvent', function() { ... });
function pollZoomFireEvent()
{
if ( ... width changed ... ) {
$(window).trigger('myZoomEvent');
}
}
Throttle/debounce can help with reducing the rate of calls of your handler.
According to MDN, "matchMedia" is the proper way to do this https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#Monitoring_screen_resolution_or_zoom_level_changes
it's a bit finicky because each instance can only watch one MQ at a time, so if you're interested in any zoom level change you need to make a bunch of matchers.. but since the browser is in charge to emitting the events it's probably still more performant than polling, and you could throttle or debounce the callback or pin it to an animation frame or something - here's an implementation that seems pretty snappy, feel free to swap in _throttle or whatever if you're already depending on that.
Run the code snippet and zoom in and out in your browser, note the updated value in the markup - I only tested this in Firefox! lemme know if you see any issues.
const el = document.querySelector('#dppx')
if ('matchMedia' in window) {
function observeZoom(cb, opts) {
opts = {
// first pass for defaults - range and granularity to capture all the zoom levels in desktop firefox
ceiling: 3,
floor: 0.3,
granularity: 0.05,
...opts
}
const precision = `${opts.granularity}`.split('.')[1].length
let val = opts.floor
const vals = []
while (val <= opts.ceiling) {
vals.push(val)
val = parseFloat((val + opts.granularity).toFixed(precision))
}
// construct a number of mediamatchers and assign CB to all of them
const mqls = vals.map(v => matchMedia(`(min-resolution: ${v}dppx)`))
// poor person's throttle
const throttle = 3
let last = performance.now()
mqls.forEach(mql => mql.addListener(function() {
console.debug(this, arguments)
const now = performance.now()
if (now - last > throttle) {
cb()
last = now
}
}))
}
observeZoom(function() {
el.innerText = window.devicePixelRatio
})
} else {
el.innerText = 'unable to observe zoom level changes, matchMedia is not supported'
}
<div id='dppx'>--</div>
You can also get the text resize events, and the zoom factor by injecting a div containing at least a non-breakable space (possibly, hidden), and regularly checking its height. If the height changes, the text size has changed, (and you know how much - this also fires, incidentally, if the window gets zoomed in full-page mode, and you still will get the correct zoom factor, with the same height / height ratio).
<script>
var zoomv = function() {
if(topRightqs.style.width=='200px){
alert ("zoom");
}
};
zoomv();
</script>
On iOS 10 it is possible to add an event listener to the touchmove event and to detect, if the page is zoomed with the current event.
var prevZoomFactorX;
var prevZoomFactorY;
element.addEventListener("touchmove", (ev) => {
let zoomFactorX = document.documentElement.clientWidth / window.innerWidth;
let zoomFactorY = document.documentElement.clientHeight / window.innerHeight;
let pageHasZoom = !(zoomFactorX === 1 && zoomFactorY === 1);
if(pageHasZoom) {
// page is zoomed
if(zoomFactorX !== prevZoomFactorX || zoomFactorY !== prevZoomFactorY) {
// page is zoomed with this event
}
}
prevZoomFactorX = zoomFactorX;
prevZoomFactorY = zoomFactorY;
});
Here is a clean solution:
// polyfill window.devicePixelRatio for IE
if(!window.devicePixelRatio){
Object.defineProperty(window,'devicePixelRatio',{
enumerable: true,
configurable: true,
get:function(){
return screen.deviceXDPI/screen.logicalXDPI;
}
});
}
var oldValue=window.devicePixelRatio;
window.addEventListener('resize',function(e){
var newValue=window.devicePixelRatio;
if(newValue!==oldValue){
// TODO polyfill CustomEvent for IE
var event=new CustomEvent('devicepixelratiochange');
event.oldValue=oldValue;
event.newValue=newValue;
oldValue=newValue;
window.dispatchEvent(event);
}
});
window.addEventListener('devicepixelratiochange',function(e){
console.log('devicePixelRatio changed from '+e.oldValue+' to '+e.newValue);
});
Here is a native way (major frameworks cannot zoom in Chrome, because they dont supports passive event behaviour)
//For Google Chrome
document.addEventListener("mousewheel", event => {
console.log(`wheel`);
if(event.ctrlKey == true)
{
event.preventDefault();
if(event.deltaY > 0) {
console.log('Down');
}else {
console.log('Up');
}
}
}, { passive: false });
// For Mozilla Firefox
document.addEventListener("DOMMouseScroll", event => {
console.log(`wheel`);
if(event.ctrlKey == true)
{
event.preventDefault();
if(event.detail > 0) {
console.log('Down');
}else {
console.log('Up');
}
}
}, { passive: false });
I'am replying to a 3 year old link but I guess here's a more acceptable answer,
Create .css file as,
#media screen and (max-width: 1000px)
{
// things you want to trigger when the screen is zoomed
}
EG:-
#media screen and (max-width: 1000px)
{
.classname
{
font-size:10px;
}
}
The above code makes the size of the font '10px' when the screen is zoomed to approximately 125%. You can check for different zoom level by changing the value of '1000px'.
Related
How should I write the width of the body of my document as a condition in JavaScript? [duplicate]
I want to provide my visitors the ability to see images in high quality, is there any way I can detect the window size? Or better yet, the viewport size of the browser with JavaScript? See green area here:
Cross-browser #media (width) and #media (height) values const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0) const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0) window.innerWidth and window.innerHeight gets CSS viewport #media (width) and #media (height) which include scrollbars initial-scale and zoom variations may cause mobile values to wrongly scale down to what PPK calls the visual viewport and be smaller than the #media values zoom may cause values to be 1px off due to native rounding undefined in IE8- document.documentElement.clientWidth and .clientHeight equals CSS viewport width minus scrollbar width matches #media (width) and #media (height) when there is no scrollbar same as jQuery(window).width() which jQuery calls the browser viewport available cross-browser inaccurate if doctype is missing Resources Live outputs for various dimensions verge uses cross-browser viewport techniques actual uses matchMedia to obtain precise dimensions in any unit
jQuery dimension functions $(window).width() and $(window).height()
You can use the window.innerWidth and window.innerHeight properties.
If you aren't using jQuery, it gets ugly. Here's a snippet that should work on all new browsers. The behavior is different in Quirks mode and standards mode in IE. This takes care of it. var elem = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; var height = elem.clientHeight; var width = elem.clientWidth;
I looked and found a cross browser way: function myFunction(){ if(window.innerWidth !== undefined && window.innerHeight !== undefined) { var w = window.innerWidth; var h = window.innerHeight; } else { var w = document.documentElement.clientWidth; var h = document.documentElement.clientHeight; } var txt = "Page size: width=" + w + ", height=" + h; document.getElementById("demo").innerHTML = txt; } <!DOCTYPE html> <html> <body onresize="myFunction()" onload="myFunction()"> <p> Try to resize the page. </p> <p id="demo"> </p> </body> </html>
I know this has an acceptable answer, but I ran into a situation where clientWidth didn't work, as iPhone (at least mine) returned 980, not 320, so I used window.screen.width. I was working on existing site, being made "responsive" and needed to force larger browsers to use a different meta-viewport. Hope this helps someone, it may not be perfect, but it works in my testing on iOs and Android. //sweet hack to set meta viewport for desktop sites squeezing down to mobile that are big and have a fixed width //first see if they have window.screen.width avail (function() { if (window.screen.width) { var setViewport = { //smaller devices phone: 'width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no', //bigger ones, be sure to set width to the needed and likely hardcoded width of your site at large breakpoints other: 'width=1045,user-scalable=yes', //current browser width widthDevice: window.screen.width, //your css breakpoint for mobile, etc. non-mobile first widthMin: 560, //add the tag based on above vars and environment setMeta: function () { var params = (this.widthDevice <= this.widthMin) ? this.phone : this.other; var head = document.getElementsByTagName("head")[0]; var viewport = document.createElement('meta'); viewport.setAttribute('name','viewport'); viewport.setAttribute('content',params); head.appendChild(viewport); } } //call it setViewport.setMeta(); } }).call(this);
I was able to find a definitive answer in JavaScript: The Definitive Guide, 6th Edition by O'Reilly, p. 391: This solution works even in Quirks mode, while ryanve and ScottEvernden's current solution do not. function getViewportSize(w) { // Use the specified window or the current window if no argument w = w || window; // This works for all browsers except IE8 and before if (w.innerWidth != null) return { w: w.innerWidth, h: w.innerHeight }; // For IE (or any browser) in Standards mode var d = w.document; if (document.compatMode == "CSS1Compat") return { w: d.documentElement.clientWidth, h: d.documentElement.clientHeight }; // For browsers in Quirks mode return { w: d.body.clientWidth, h: d.body.clientHeight }; } except for the fact that I wonder why the line if (document.compatMode == "CSS1Compat") is not if (d.compatMode == "CSS1Compat"), everything looks good.
If you are looking for non-jQuery solution that gives correct values in virtual pixels on mobile, and you think that plain window.innerHeight or document.documentElement.clientHeight can solve your problem, please study this link first: https://tripleodeon.com/assets/2011/12/table.html The developer has done good testing that reveals the problem: you can get unexpected values for Android/iOS, landscape/portrait, normal/high density displays. My current answer is not silver bullet yet (//todo), but rather a warning to those who are going to quickly copy-paste any given solution from this thread into production code. I was looking for page width in virtual pixels on mobile, and I've found the only working code is (unexpectedly!) window.outerWidth. I will later examine this table for correct solution giving height excluding navigation bar, when I have time.
This code is from http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/ function viewport() { var e = window, a = 'inner'; if (!('innerWidth' in window )) { a = 'client'; e = document.documentElement || document.body; } return { width : e[ a+'Width' ] , height : e[ a+'Height' ] }; } NB : to read the width, use console.log('viewport width'+viewport().width);
There is a difference between window.innerHeight and document.documentElement.clientHeight. The first includes the height of the horizontal scrollbar.
A solution that would conform to W3C standards would be to create a transparent div (for example dynamically with JavaScript), set its width and height to 100vw/100vh (Viewport units) and then get its offsetWidth and offsetHeight. After that, the element can be removed again. This will not work in older browsers because the viewport units are relatively new, but if you don't care about them but about (soon-to-be) standards instead, you could definitely go this way: var objNode = document.createElement("div"); objNode.style.width = "100vw"; objNode.style.height = "100vh"; document.body.appendChild(objNode); var intViewportWidth = objNode.offsetWidth; var intViewportHeight = objNode.offsetHeight; document.body.removeChild(objNode); Of course, you could also set objNode.style.position = "fixed" and then use 100% as width/height - this should have the same effect and improve compatibility to some extent. Also, setting position to fixed might be a good idea in general, because otherwise the div will be invisible but consume some space, which will lead to scrollbars appearing etc.
For detect the Size dynamically You can do it In Native away, without Jquery or extras console.log('height default :'+window.visualViewport.height) console.log('width default :'+window.visualViewport.width) window.addEventListener('resize',(e)=>{ console.log( `width: ${e.target.visualViewport.width}px`); console.log( `height: ${e.target.visualViewport.height}px`); });
This is the way I do it, I tried it in IE 8 -> 10, FF 35, Chrome 40, it will work very smooth in all modern browsers (as window.innerWidth is defined) and in IE 8 (with no window.innerWidth) it works smooth as well, any issue (like flashing because of overflow: "hidden"), please report it. I'm not really interested on the viewport height as I made this function just to workaround some responsive tools, but it might be implemented. Hope it helps, I appreciate comments and suggestions. function viewportWidth () { if (window.innerWidth) return window.innerWidth; var doc = document, html = doc && doc.documentElement, body = doc && (doc.body || doc.getElementsByTagName("body")[0]), getWidth = function (elm) { if (!elm) return 0; var setOverflow = function (style, value) { var oldValue = style.overflow; style.overflow = value; return oldValue || ""; }, style = elm.style, oldValue = setOverflow(style, "hidden"), width = elm.clientWidth || 0; setOverflow(style, oldValue); return width; }; return Math.max( getWidth(html), getWidth(body) ); }
If you are using React, then with latest version of react hooks, you could use this. // Usage function App() { const size = useWindowSize(); return ( <div> {size.width}px / {size.height}px </div> ); } https://usehooks.com/useWindowSize/
It should be let vw = document.documentElement.clientWidth; let vh = document.documentElement.clientHeight; understand viewport: https://developer.mozilla.org/en-US/docs/Web/CSS/Viewport_concepts shorthand for link above: viewport.moz.one I've built a site for testing on devices: https://vp.moz.one
you can use window.addEventListener('resize' , yourfunction); it will runs yourfunction when the window resizes. when you use window.innerWidth or document.documentElement.clientWidth it is read only. you can use if statement in yourfunction and make it better.
You can simply use the JavaScript window.matchMedia() method to detect a mobile device based on the CSS media query. This is the best and most reliable way to detect mobile devices. The following example will show you how this method actually works: <script> $(document).ready(function(){ if(window.matchMedia("(max-width: 767px)").matches){ // The viewport is less than 768 pixels wide alert("This is a mobile device."); } else{ // The viewport is at least 768 pixels wide alert("This is a tablet or desktop."); } }); </script>
True/False depending on screen size dynamically?
I'm following a guide that allows Google Map screen to disable scrolling depending on the screen size. The only part i'm struggling is to write a code that dynamically changes the True/False value when i resize the screen manually. This is the website that I followed the instruction but I can't seem to write the correct syntax code to produce the dynamic true false value depending on the screen size https://coderwall.com/p/pgm8xa/disable-google-maps-scrolling-on-mobile-layout Part of the code that i need to use: $(window).resize() And then: setOptions() So I'm struggling to combine them together. I have tried something like this: var dragging = $(window).width(function resize() { if (dragging > 560) { return true; } else { return false; } });
The article you linked to is lacking important information as it fails to mention that $ is (presumably) jQuery. But you don't need jQuery at all. What you can use instead is the MediaQueryList. It is similar to media queries in CSS, but it is a JavaScript API. The following is an untested example of how you might use it with a MediaQueryList event listener. It sets the initial value and listens to changes to your media query with a handler that uses setOptions from the Google Maps API. var mql = window.matchMedia('(min-width: 560px)'); var isDraggable = mql.matches; var map; function initMap() { map = new google.maps.Map(document.getElementById('map'), { draggable: isDraggable }); } function mqChange(e) { map.setOptions({draggable: !!e.matches}); } mql.addListener(mqChange);
You could add an event listener to the resize event and set a value of your variable whenever the size of the window is changed: var dragging = false; window.addEventListener('resize', function(event) { dragging = window.innerWidth > 560; }); Since you mentioned that you want to disable scrolling when the windows size extends a certain value, it might be easier to just do this. If you try it you can see in the console that the value changes whenever you resize your window): window.addEventListener('resize', function(event) { console.log(window.innerWidth); if (window.innerWidth > 560) { // disable scrolling or do whatever you want to do } }); BTW, in your code you do this: if (dragging > 560) { return true; } else { return false; } You can simplify this to: return dragging > 560 Which is exactly the same.
You can use this function to get the width and height on a resize of the screen. $(window).resize(function() { $windowWidth = $(window).width(); $windowHeight = $(window).height(); // run other functions or code }); But, if you want to only show/hide a html element based on the screen size, you can also use plain html/css. <div id="maps"></div> Css: #media only screen and (max-width: 560px) { #maps { display: none; } }
you can use the matchMedia function to run a callback whenever the media query status is changing var mql = window.matchMedia('(min-width: 700px)'); function mediaHandler(e) { if (e.matches) { /* the viewport is more than 700 pixels wide */ } else { /* the viewport is 700 pixels wide or less */ } } mql.addListener(mediaHandler);
How to detect a browser screen width increase past a certain point using jQuery?
basically, what I want to do is trigger an event if the user increases the size of the browser from X to Y. Provided X = Anything less than 750 pixels, and Y is anything more than 750 pixels. Right now, I am doing something like this: $(window).resize(function(){ if ($(window).width() >= 750) { console.log('750 or more'); } }); This works, however, its clearly not efficient. For example, if I resize my window from 780px to max width (1024px), even then the event gets triggered. Or even if I decrease the size from 800px to 780px, I still obviously get the console output. How do I get this to work right?
You will need to setTimeout to allow check to take place . Example : var resizeTimer; $(window).resize(function() { clearTimeout(resizeTimer); resizeTimer = setTimeout(function() { var body_size = $(window).width(); // ... // do your screen check here // ... }, 1); }) Hope this helps
There's no true solution for this issue since removing the on resize event after max width has been reached results in the on resize function no longer being called even when the width is below 1024px. Maybe in the future it's possible to have an on resize event under certain conditions only. You can also use the on resize end event to only trigger the function after resizing the window, keep in mind this might result in visual changes happening after a user has resized a window instead of during the resizing of a window. There are multiple methods to make the on resize event perform better: http://bencentra.com/code/2015/02/27/optimizing-window-resize.html
Here is a throttled version using script that might be a good start Fiddle demo (function(timeout,bigger) { // local static var - timeout,bigger window.addEventListener("resize", function(e) { if ( !timeout ) { timeout = setTimeout(function() { timeout = null; actualResizeHandler(e); // Set the actual fire rate }, 66); } }, false); function actualResizeHandler(e) { // handle the resize event if (window.innerWidth >= 750 && !bigger) { //passed above (or equal) 750 document.querySelector('span').style.color = 'blue'; document.body.innerHTML += '<br>above 750'; } else if (window.innerWidth < 750 && bigger) { //passed below 750 document.querySelector('span').style.color = 'red'; document.body.innerHTML += '<br>below 750'; } bigger = (window.innerWidth >= 750); } // run once at load bigger = (window.innerWidth < 750); actualResizeHandler(); }(null,false)); <span>This text is blue on big and red on small</span> and here is one use CSS media query span { color: red; } #media screen and (min-width: 750px) { span { color: blue } } <span>This text is blue on big and red on small</span>
How to change pop-up location of google charts tooltip
I currently have html enabled tooltips that also display "sub graphs". However, it would be nice if it was possible to have all tooltips pop up in a fixed location or have an offset that adjusted their relative poition. This is an example of the kind of tooltip that I have (blank data). I'd like to move it to the right. Any suggestions would be appreciated, including any javascript trickery.
whilst the answer is very good it is a little outdated now. Google has implemented CSS control so there is greater flexibility without the need to hack the JavaScript. .google-visualization-tooltip { position:relative !important; top:0 !important;right:0 !important; z-index:+1;} will provide a tooltip fixed at the bottom of the chart, live example: http://www.taxformcalculator.com/federal-budget/130000.html alternatively you could just tweak the left margin... .google-visualization-tooltip { margin-left: 150px !important; z-index:+1;} Note that pulling the container forward with z-index reduces (but does not stop entirely) visibility flicker as the mouse moves. The degree of flicker will vary on chart size, call etc. Personally, I prefer to fix the tool tip and make it part of the design as per the first example. Hope this helps those who are deterred by the JS hack (which is good but really no longer necessary).
The tooltip position is set inline, so you need to listen for DOM insertion of the tooltip and change the position manually. Mutation events are deprecated, so use a MutationObserver if it is available (Chrome, Firefox, IE11) and a DOMNodeInserted event handler if not (IE 9, 10). This will not work in IE8. google.visualization.events.addOneTimeListener(myChart, 'ready', function () { var container = document.querySelector('#myChartDiv > div:last-child'); function setPosition () { var tooltip = container.querySelector('div.google-visualization-tooltip'); tooltip.style.top = 0; tooltip.style.left = 0; } 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); } }); The MutationObserver should be fine, but the events may need some work; I didn't test them.
I had more or less the same question as Redshift, having been trying to move the tooltip relative to the node being hovered over. Using asgallant's fantastic answer I've implemented his code as below. I haven't been able to test whether this works with the MutationObserver because during my testing in Firefox, Chrome and IE11 it always fails that test and uses addEventListener. The docs suggest it should work though. I had to introduce a timeout to actually manipulate the styles as otherwise the left and top position of the element was always reported as 0. My assumption is that the event fired upon addition of the node but the DOM wasn't quite ready. This is just a guess though and I'm not 100% happy with implementing it in this way. var chart = new google.visualization.LineChart(document.getElementById('line_chart')); google.visualization.events.addOneTimeListener(chart, 'ready', function () { var container = document.querySelector('#line_chart > div:last-child'); function setPosition(e) { if (e && e.target) { var tooltip = $(e.target); setTimeout(function () { var left = parseFloat(tooltip.css('left')) - 49; var top = parseFloat(tooltip.css('top')) - 40; tooltip.css('left', left + 'px'); tooltip.css('top', top + 'px'); $(".google-visualization-tooltip").fadeIn(200); }, 1); } else { var tooltip = container.querySelector('.google-visualization-tooltip'); var left = parseFloat(tooltip.style.left) - 49; var top = parseFloat(tooltip.style.top) - 40; tooltip.style.left = left + 'px'; tooltip.style.top = top + 'px'; $(".google-visualization-tooltip").fadeIn(200); } } if (typeof MutationObserver === 'function') { var observer = new MutationObserver(function (m) { if (m.length && m[0].addedNodes.length) { setPosition(m); } }); observer.observe(container, { childList: true }); } else if (document.addEventListener) { container.addEventListener('DOMNodeInserted', setPosition); } else { container.attachEvent('onDOMNodeInserted', setPosition); } }); chart.draw(data, options); } EDIT: Updated to get the MutationObserver working following asgallant's comment.
scaling divs and images css/javascript depending on the screen
I have div which has inside few divs, few images and two selects. I want to make my main division and all of its content to automatically resize depending on the screen. How can I do it? Thank you :)
You use media queries for this. It is called responsive design #media screen and (max-width: 699px) { div { width: 40px; } } This will essentially change the width of div to 40px only if the screen width is less than 699px Further reference: CSS-Tricks
Here is a tried-and-tested script which even accomodates prehistoric browsers such as IE4. It takes the viewport approach, which means divisions can be updated when a user resizes their browser window. <script> window.onResize = function() { if (window.innerWidth) { // All browsers but IE myViewportWidth = window.innerWidth; myViewportHeight = window.innerHeight; } else if (document.documentElement && document.documentElement.clientWidth) { // These functions are for IE6 when there is a DOCTYPE myViewportWidth = document.documentElement.clientWidth; myViewportHeight = document.documentElement.clientHeight; } else if (document.body.clientWidth) { // These are for IE4, IE5, and IE6 without a DOCTYPE myViewportWidth = document.body.clientWidth; myViewportHeight = document.body.clientHeight; } // now call customResize with your chosen new dimensions // you'll probably need to insert a bit of arithmetic here: // *calculate new values here* customResize( MY_NEW_X_VALUE, MY_NEW_Y_VALUE ); }// function </script> Once you have the viewport dimensions you can resize your main division according to the specific dimensions of the viewport. I generally use one main division for the content placed inside the 'body' element for convenience. Then modify the following script according to the dimensions you need. <script> function customResize(newWidth, newHeight){ var X = newWidth; var Y = newHeight; var e = document.getElementById('mainDiv').style.width = 'X'; var f = document.getElementById('mainDiv').style.height = 'Y'; </script> Take care to test the code with different browsers however - sometimes odd versions of browsers can return unusual values.