fit image to screen properly in javascript - javascript

I need to resize image from its natural size to fit the screen the same way as Chrome does with opened images in it, I wrote a rescale() function for this purpose (below).
It works mostly fine but for big landscape-oriented images (example where both width and height both exceed screen after resizing with my function http://imageontime.com/upload/big/2013/07/20/51ea60b522bba.jpg ) fullscreened image still exceeds screen by few lines at height (and rarely at width), so i wanted to ask if there is a better rescale javascript function out there or if here are any chromium source adepts who could look into chromiums source code to get the image resizing function from it so I could port it into javascript?
Here's the code:
function setautow() {
img.style.width = 'auto';
img.style.removeProperty("height");
if (document.documentElement.clientHeight == 0) // Firefox again...
{
img.height = window.innerHeight;
}
else {
img.height = document.documentElement.clientHeight;
}
}
function setautoh() {
img.style.height = 'auto';
img.style.removeProperty("width");
if (document.documentElement.clientWidth == 0) // FF
{
img.width = window.innerWidth;
}
else {
img.width = document.documentElement.clientWidth;
}
}
function shrink(a) {
if (a) {
if (img.width != document.documentElement.clientWidth) {
setautoh();
}
}
else {
if (img.height != document.documentElement.clientHeight) {
setautow();
}
}
}
var rescaled = false;
function rescale() {
if (rescaled) {
rescaled = false;
img.height = img.naturalHeight;
img.width = img.naturalWidth;
img.style.removeProperty("height");
img.style.removeProperty("width");
}
else {
rescaled = true;
if (img.naturalWidth > img.naturalHeight) {
setautoh();
setTimeout(function () {
shrink(true);
}, 0);
}
else {
setautow();
setTimeout(function () {
shrink(false);
}, 0);
}
}
}

The following seems to do the job nicely, as long as image width/height is not specified in CSS.
#Javascript
window.onresize = window.onload = function()
{
resize();
}
function resize()
{
var img = document.getElementsByTagName('img')[0];
winDim = getWinDim();
img.style.height = winDim.y + "px";
if (img.offsetWidth > winDim.x)
{
img.style.height = null;
img.style.width = winDim.x + "px";
}
}
function getWinDim()
{
var body = document.documentElement || document.body;
return {
x: window.innerWidth || body.clientWidth,
y: window.innerHeight || body.clientHeight
}
}
#CSS
body{
margin:0;
padding:0;
text-align:center;
background:rgb(51, 51, 51);
}
#HTML
<img src="http://placehold.it/4000x3000" />

Finally made what I was looking for, works great for FireFox + Chrome
edit: well, perfect for images larger than screen, gonna work on it so it could work on smaller images
function fit_to_screen()
{
img.removeAttribute("style");
var winX = window.innerWidth + "px";
var winY = window.innerHeight + "px";
var vbar = false;
if (document.body.scrollHeight > document.body.clientHeight) // vertical scrollbar
{
img.style.height = winY;
vbar = true;
}
if (document.body.scrollWidth > document.body.clientWidth) // horizontal scrollbar
{
if (vbar) // both scrollbars
{
if ((document.body.scrollHeight - document.body.clientHeight) > (document.body.scrollWidth - document.body.clientWidth)) // let's see which one is bigger
{
img.removeAttribute("style");
img.style.height = winY;
}
else
{
img.removeAttribute("style");
img.style.width = winX;
}
}
else
{
img.removeAttribute("style");
img.style.width = winX;
}
}
}
// bonus, switch between original size and fullscreen
var rescaled = false;
function rescale()
{
if (rescaled)
{
rescaled = false;
img.removeAttribute("style");
}
else
{
rescaled = true;
fit_to_screen();
}
}

Related

Safari & Chrome Giving diffrent results to the same script (document.querySelector)

Why are Safari and Chrome giving different results when using document.querySelector in the same script?
What I'm trying to do is display the image next to the link when hovering over it. The image should be displayed next to the link.
In Safari, the image is displayed properly from the left corner, but in Chrome, when I scroll down and point at the link, the image is displayed from unexpected angles.
JavaScript:
let attached = false;
function showImage() {
const image = document.querySelector('img');
if (image && !attached) {
attached = true;
image.style.display = 'block';
document.addEventListener('pointermove', function(event) {
image.style.left = event.x + 'px';
image.style.top = event.y + 'px';
});
}
}
function hideImage() {
const image = document.querySelector('img');
if (image && attached) {
attached = false;
image.style.display = 'none';
document.removeEventListener('pointermove', function(event) {
image.style.left = event.x + 'px';
image.style.top = event.y + 'px';
});
}
}
CSS:
img{
position: fixed;
display: none;
pointer-events: none;
width: 640px;
height: auto;
}
I've tried changing the code to:
let attached = false;
const getElmtImage = (elmt) => {
return elmt.querySelector("img")
}
const followMouse = (elmt, event) => {
elmt.style.left = event.x + "px";
elmt.style.top = event.y + "px";
}
function showImage(elmt) {
const image = getElmtImage(elmt)
if (!attached) {
attached = true;
image.style.display = "block";
document.addEventListener("pointermove", function(event) {
followMouse(image, event)
});
}
}
function hideImage(elmt) {
const image = getElmtImage(elmt)
attached = false;
image.style.display = "none";
document.removeEventListener("pointermove", followMouse);
}```
I have conducted some testing, and it appears that Chrome and Safari handle events differently (based on my testing, although I could be mistaken). In Safari, event.x works, whereas in Chrome only event.pageY works. To work around this issue, I first check the browser type and then execute the appropriate functions. This approach may not be the cleanest, but it is effective. If you have a better idea of how to handle this situation, please share it.
let attached = false;
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf('safari') != -1) {
if (ua.indexOf('chrome') > -1) {
// chrome
function showImage() {
const image = document.querySelector('img');
if (image && !attached) {
attached = true;
image.style.display = 'block';
document.addEventListener('mousemove', function(event) {
image.style.left = event.pageX + 'px';
image.style.top = event.pageY + 'px';
});
}
}
function hideImage() {
const image = document.querySelector('img');
if (image && attached) {
attached = false;
image.style.display = 'none';
document.removeEventListener('mousemove', function(event) {
image.style.left = event.pageX + 'px';
image.style.top = event.pageY + 'px';
});
}
} } else {
// safari
function showImage() {
const image = document.querySelector('img');
if (image && !attached) {
attached = true;
image.style.display = 'block';
document.addEventListener('pointermove', function(event) {
image.style.left = event.x + 'px';
image.style.top = event.y + 'px';
});
}
}
function hideImage() {
const image = document.querySelector('img');
if (image && attached) {
attached = false;
image.style.display = 'none';
document.removeEventListener('pointermove', function(event) {
image.style.left = event.x + 'px';
image.style.top = event.y + 'px';
});
}
} }
}

Match image container width with image width after it is rendered - React

I am using react-image-marker which overlays marker on image inside a div.
<ImageMarker
src={props.asset.url}
markers={markers}
onAddMarker={(marker) => setMarkers([...markers, marker])}
className="object-fit-contain image-marker__image"
/>
The DOM elements are as follows:
<div class=“image-marker”>
<img src=“src” class=“image-marker__image” />
</div>
To make vertically long images fit the screen i have added css to contain the image within div
.image-marker {
width: inherit;
height: inherit;
}
.image-marker__image {
object-fit:contain !important;
width: inherit;
height: inherit;
}
But now the image is only a subpart of the entire marker area. Due to which marker can be added beyond image bounds, which i do not want.
How do you think i can tackle this. After the image has been loaded, how can i change the width of parent div to make sure they have same size and markers remain in the image bounds. Please specify with code if possible
Solved it by adding event listeners in useLayoutEffect(). Calculating image size info after it is rendered and adjusting the parent div dimensions accordingly. Initially and also when resize occurs.
If you think you have a better solution. Do specify.
useLayoutEffect(() => {
const getRenderedSize = (contains, cWidth, cHeight, width, height, pos) => {
var oRatio = width / height,
cRatio = cWidth / cHeight;
return function () {
if (contains ? (oRatio > cRatio) : (oRatio < cRatio)) {
this.width = cWidth;
this.height = cWidth / oRatio;
} else {
this.width = cHeight * oRatio;
this.height = cHeight;
}
this.left = (cWidth - this.width) * (pos / 100);
this.right = this.width + this.left;
return this;
}.call({});
}
const getImgSizeInfo = (img) => {
var pos = window.getComputedStyle(img).getPropertyValue('object-position').split(' ');
return getRenderedSize(true,
img.width,
img.height,
img.naturalWidth,
img.naturalHeight,
parseInt(pos[0]));
}
const imgDivs = reactDom.findDOMNode(imageCompRef.current).getElementsByClassName("image-marker__image")
if (imgDivs) {
if (imgDivs.length) {
const thisImg = imgDivs[0]
thisImg.addEventListener("load", (evt) => {
if (evt) {
if (evt.target) {
if (evt.target.naturalWidth && evt.target.naturalHeight) {
let renderedImgSizeInfo = getImgSizeInfo(evt.target)
if (renderedImgSizeInfo) {
setOverrideWidth(Math.round(renderedImgSizeInfo.width))
}
}
}
}
})
}
}
function updateSize() {
const thisImg = imgDivs[0]
if (thisImg){
let renderedImgSizeInfo = getImgSizeInfo(thisImg)
if (renderedImgSizeInfo) {
setOverrideWidth((prev) => {
return null
})
setTimeout(() => {
setOverrideWidth((prev) => {
return setOverrideWidth(Math.round(renderedImgSizeInfo.width))
})
}, 390);
}
}
}
window.addEventListener('resize', updateSize);
return () => window.removeEventListener('resize', updateSize);
}, [])

style.pointerEvents not functioning

I'm trying to make an element that shrinks as you click it more and more. Once it reaches a threshold of 1%, it should reappear in full length and not be clickable. the style.pointerEvents is not working. (This is code added in, in order to solve an issue.) This is all of the code, there must be conflicting variables or something. But the main premise is to shake the element and shrink and then regrow and disable itself and after a waiting period enable itself.
`var rotated = false;
var height = 24.6;
var width = 15
function clickedhub() {
clicked();
timeout();
}
function clicked() {
document.getElementById('box').onclick = function() {
var div = document.getElementById('box'),
deg = rotated ? 0 : 10;
div.style.webkitTransform = 'rotate('+deg+'deg)';
div.style.msTransform = 'rotate('+deg+'deg)';
div.style.oTransform = 'rotate('+deg+'deg)';
div.style.transform = 'rotate('+deg+'deg)';
}
setInterval(res, 140);
function res() {
document.getElementById('box').style = function() {
var div = document.getElementById('box'),
deg = rotated ? 0 : 0;
div.style.webkitTransform = 'rotate('+deg+'deg)';
div.style.mozTransform = 'rotate('+deg+'deg)';
div.style.msTransform = 'rotate('+deg+'deg)';
div.style.oTransform = 'rotate('+deg+'deg)';
div.style.transform = 'rotate('+deg+'deg)';
}
}
}
function timeout() {
document.getElementById('box').onclick = function() {
var div = document.getElementById('box');
width = width / 1.5;
height = height / 1.5;
}
}
setInterval(gamerule, 10);
function gamerule() {
var div = document.getElementById('box');
if (width <= 1) {
div.removeEventListener("click", gamerule);
width = 100;
height = 100;
} else {
width--;
height--;
}
div.style.width = width + '%';
div.style.height = height + '%';
div.addEventListener("click", gamerule);
}
`
This should work for you
//setInterval(gamerule, 10);
let width = 100;
let height = 100;
var div = document.getElementById('box');
function gamerule() {
if (width <= 1) {
div.removeEventListener("click", gamerule);
width = 100;
height = 100;
} else {
width--;
height--;
}
div.style.width = width + '%';
div.style.height = height + '%';
}
div.addEventListener("click", gamerule);
#box{
background-color:red;
width:100%;
height:100%;
}
#container{
width:500px;
height:500px;
}
Click on the red box
<div id="container" >
<div id="box">
</div>
</div>

How to move an image depending on mouse location using JS?

I would like an image to move to the left if the mouse is to the left of the screen and to the right if the mouse to the right of the screen, using javascript, here is the code I have so far:
var dirx = 0;
var spdx = 35;
var imgLeftInt;
var imgTopInt;
var imgHeight;
var imgWidth;
var divWidth;
var divHeight;
var t;
var tempX;
var tempY;
So I'm pretty sure I'm not missing any variables...
function animBall(on) {
imgLeftInt = parseInt(document.images['logo'].style.left);
imgTopInt = parseInt(document.images['logo'].style.top);
imgHeight = parseInt(document.images['logo'].height);
imgWidth = parseInt(document.images['logo'].width);
divWidth = parseInt(document.images['container'].width);
if (tempX > 779){
dirx = 1;
}
else if(tempX < 767){
dirx = 2;
}
else {
spdx = 0;
}
So if tempX, which should be the x coordinate of the mouse location, is bigger than 779, which is the halfway point of the div tag, the image should go right. If it's less than that, it should go left, and otherwise, the speed should be zero, as in it should stay still.
if(dirx == 1){
goRight();
} else if(dirx == 2) {
goLeft();
}
}
function getMouseXY(e) {
tempX = e.clientX;
tempY = e.clientY;
}
I found hundreds of different ways to get the mouse location, but this was off W3C so I assume it works.
function goRight() {
document.images['logo'].style.left = imgLeftInt+spdx +"px";
if (imgLeftInt > (divWidth-imgWidth)){
dirx = 2;
spdx= 20;
}
}
function goLeft() {
document.images['logo'].style.left = (imgLeftInt-spdx) +"px";
if (imgLeftInt < 5){
dirx = 1;
spdx= 20;
}
}
</script>
So that's my whole script.
<div id="container" onmousemove="getMouseXY(event);" width="1546" height="423">
Start Animation Stop Animation <br />
<img src="http://qabila.tv/images/logo_old.png" style="position:absolute;left:10px;top:20px;" id="logo" />
</div>
I left the dependency on the mouse location to the very end so the animation script works fine (or at least worked, unless I broke something trying to get it to read the mouse location).
Any ideas what I'm doing wrong??
If it's any help, I've hosted the code here.
I went to your link and tried debugging your code. I get an error on line 21 because your document has no "container" image ("container" is a div).
At the start of your question, you said you wanted to know mouse position relative to center of "screen". For that, you'd probably want to use window.innerWidth instead of the width attribute that you set on your div.
Well that needed a whole load of work, anyway, I have done some of it for you and you can now see things partially working, but you will need to play with it on jsfiddle. Perhaps you can now open some specific questions regarding getting this to work.
<div id="container" width="1546" height="423"> <a id="start" href="#">Start Animation</a> <a id="stop" href="#">Stop Animation</a>
<br />
<img src="http://qabila.tv/images/logo_old.png" style="position:absolute;left:10px;top:20px;" id="logo" />
</div>
/*jslint sub: true, maxerr: 50, indent: 4, browser: true */
/*global */
(function () {
"use strict";
var start = document.getElementById("start"),
stop = document.getElementById("stop"),
container = document.getElementById("container"),
logo = document.getElementById("logo"),
dirx = 0,
spdx = 35,
imgLeftInt,
imgTopInt,
imgHeight,
imgWidth,
divWidth,
divHeight,
t,
tempX,
tempY;
function getMouseXY(e) {
tempX = e.clientX;
tempY = e.clientY;
}
function goRight() {
logo.style.left = imgLeftInt + spdx + "px";
if (imgLeftInt > (divWidth - imgWidth)) {
dirx = 2;
spdx = 20;
}
}
function goLeft() {
logo.style.left = (imgLeftInt - spdx) + "px";
if (imgLeftInt < 5) {
dirx = 1;
spdx = 20;
}
}
// attribute on unused
function animBall(on) {
imgLeftInt = parseInt(logo.style.left, 10);
imgTopInt = parseInt(logo.style.top, 10);
imgHeight = parseInt(logo.height, 10);
imgWidth = parseInt(logo.width, 10);
divWidth = parseInt(container.width, 10);
if (tempX > 779) {
dirx = 1;
} else if (tempX < 767) {
dirx = 2;
} else {
spdx = 0;
}
if (dirx === 1) {
goRight();
} else if (dirx === 2) {
goLeft();
}
}
function startAnim() {
t = setInterval(animBall, 80);
}
start.addEventListener("click", startAnim, false);
function stopAnim() {
clearInterval(t);
}
stop.addEventListener("click", stopAnim, false);
container.addEventListener("mousemove", getMouseXY, false);
}());
Why don't you usee the html5 canvas and gee.js
Here's the js fiddle result (it may take a while to load, but that's fault of jsfiddle, the script will load much faster once on your website): http://jsfiddle.net/wLCeE/7/embedded/result/
and here's the much simpler code to make it work:
var g = new GEE({
width: 500,
height: 423,
container: document.getElementById('canvas')
});
var img = new Image(); // Create new img element
img.onload = function () {
demo(g)
};
img.src = 'http://qabila.tv/images/logo_old.png'; // Set source path
function demo(g) {
var style = "left"
g.draw = function () {
if (g.mouseX > g.width / 2 && style == "left") styleRight()
else if (g.mouseX < g.width / 2 && style == "right") styleLeft()
}
function styleLeft() {
style = "left"
g.ctx.clearRect(0, 0, g.width, g.height)
g.ctx.drawImage(img, 0, 0)
}
function styleRight() {
style = "right"
g.ctx.clearRect(0, 0, g.width, g.height)
g.ctx.drawImage(img, g.width - img.width, 0)
}
}

Image() onLoad not waiting for image to load

I've figured out the centering and resizing issues, but I still can't get onLoad to work properly. Anyone have any ideas? I thought onLoad was supposed to wait for the image to be loaded completely before firing the code. As this is right now, it resizes the img for the next img, and fades it in before it's loaded, so the previous image fades in again. Once the show has run through once, it works perfectly, so obviously it's not waiting for the image to load completely before firing imageLoad().
<div id="slideShow">
<div id="slideShowImg" style="display:none; margin-right:auto; margin-left:auto;">
</div>
<div id="slideShowThumbs">
</div>
<script type="text/javascript">
loadXMLDoc('http://www.thehoppr.com/hopspots/82/82.xml', function() {
var slideShow = document.getElementById('slideShow');
var items = [];
var nl = xmlhttp.responseXML.getElementsByTagName('image');
var i = 0;
var t;
var slideShowImg = document.getElementById('slideShowImg');
var slideShow = document.getElementById('slideShow');
var maxHeight = 300;
var maxWidth = 800;
var imgNode = new Image();
function image() {
var nli = nl.item(i);
var src = nli.getAttribute('src').toString();
var width = parseInt(nli.getAttribute('width').toString());
var height = parseInt(nli.getAttribute('height').toString());
imgNode.onLoad = imageLoad();
imgNode.src = src;
imgNode.height = height;
imgNode.width = width;
imgNode.setAttribute("style", "margin-right:auto; margin-left:auto; display:block;");
var ratio = maxHeight / maxWidth;
if (imgNode.height / imgNode.width > ratio) {
// height is the problem
if (imgNode.height > maxHeight) {
imgNode.width = Math.round(imgNode.width * (maxHeight / imgNode.height));
imgNode.height = maxHeight;
}
} else {
// width is the problem
if (imgNode.width > maxHeight) {
imgNode.height = Math.round(imgNode.height * (maxWidth / imgNode.width));
imgNode.width = maxWidth;
}
}
}
function imageLoad() {
slideShowImg.appendChild(imgNode);
Effect.Appear('slideShowImg', {
duration: 1
});
t = setTimeout(nextImage, 7000);
}
function nextImage() {
slideShowImg.setAttribute("style", "display:none");
if (i < nl.length - 1) {
i++;
image();
} else {
i = 0;
image();
}
}
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//XML Loaded, create the slideshow
alert(xmlhttp.responseText);
image();
}
});
</script>
Here are some of my thoughts (it's all open discussion)...
Preloading - Since you're limited to downloading 2 resources in parallel per hostname, it may not make sense to preload everything up front. Since it's a slideshow, how about modifying image() to download the i + 1 image through an Image object that doesn't get appended to the DOM? It doesn't seem beneficial to prefetch i + 2 and beyond in a slideshow setting.
Centering the images - Regarding using the auto margin width for horizontal centering, I believe you'll have to explicitly set the image to display:block. Obviously that doesn't solve centering vertically. Are all the images the same size? Also, will the slideShowImg div have a defined height/width? If so, then some math can be applied to achieve the centering.
Hope this helps! :)
Ok so I fixed the issue with the onLoad, and I even added a little preloading to help the slideshow along as well. All I had to do was define the onload first, and then do everything else except define the src inside the onload's function. I then added a little nextImg preloading so there's little if no hiccup between images even if it's the first time the browser is loading them. Here's the final code for anyone who has similar onload issues and finds there way here:
<div id="slideShow">
<div id="slideShowImg" style="display:none; margin-right:auto; margin-left:auto;">
</div>
<div id="slideShowThumbs">
</div>
<script type="text/javascript">
loadXMLDoc('/82.xml', function() {
var slideShow = document.getElementById('slideShow');
var items = [];
var nl = xmlhttp.responseXML.getElementsByTagName('image');
var i = 0;
var t;
var slideShowImg = document.getElementById('slideShowImg');
var slideShow = document.getElementById('slideShow');
var maxHeight = 300;
var maxWidth = 800;
var curImg = new Image();
var nextImg = new Image();
function image() {
var cli = nl.item(i);
var src = cli.getAttribute('src').toString();
var width = parseInt(cli.getAttribute('width').toString());
var height = parseInt(cli.getAttribute('height').toString());
curImg.onload = function() {
curImg.height = height;
curImg.width = width;
curImg.setAttribute("style", "margin-right:auto; margin-left:auto; display:block;");
slideShowImg.appendChild(curImg);
var ratio = maxHeight / maxWidth;
if (curImg.height / curImg.width > ratio) {
// height is the problem
if (curImg.height > maxHeight) {
curImg.width = Math.round(curImg.width * (maxHeight / curImg.height));
curImg.height = maxHeight;
}
} else {
// width is the problem
if (curImg.width > maxHeight) {
curImg.height = Math.round(curImg.height * (maxWidth / curImg.width));
curImg.width = maxWidth;
}
}
}
curImg.src = src;
if (i < nl.length - 1) {
var nli = nl.item(i + 1);
var nsrc = nli.getAttribute('src').toString();
nextImg.src = nsrc;
}
Effect.Appear('slideShowImg', {
duration: 1
});
t = setTimeout(nextImage, 7000);
}
function imageLoad() {}
function nextImage() {
slideShowImg.removeChild(curImg);
slideShowImg.setAttribute("style", "display:none");
if (i < nl.length - 1) {
i++;
image();
} else {
i = 0;
image();
}
}
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//XML Loaded, create the slideshow
alert(xmlhttp.responseText);
image();
}
});
</script>

Categories