I'm coding a very tiny small feature, but I'm having problems with the scroll. I need to do a zoom of a div scaling with css:
transform: scale(X,Y)
But my problem is that I don't have a correct left and top scroll in the parent div. I need to know how to calculate the new left and top each time the user press the button "More zoom", I could use translate css property if it is mandatory.
I can use jQuery, but I think this is just a math problem :)
One detail: I need that the image grow from the center.
Picture:
Here is the fiddle:
Fiddle example
i believe you need to mind transform-origin too:
// get element references
var foo = document.querySelector('#foo');
var bar = document.querySelector('#bar');
// fit bar into foo
// the third options argument is optional, see the README for defaults
// https://github.com/soulwire/fit.js
var zoom = 1;
var trans = 50;
var moreZoom = document.querySelector('#moreZoom');
moreZoom.onclick = function(e){
console.log(foo);
bar.style.transform = 'scale(' + (zoom + 0.1) + ',' + (zoom + 0.1) + ')';
zoom = (zoom + 0.1);
bar.style.transformOrigin = (50 / zoom) +'px ' +(50 / zoom )+'px';
}
#foo {
background: #36D7B7;
height: 200px;
width: 400px;
padding: 50px;
overflow: auto;
}
#bar {
background-image: url('http://www.space.com/images/i/000/028/001/original/wing-small-magellanic-cloud-galaxy-1920.jpg?interpolation=lanczos-none&fit=around%7C1440:900&crop=1440:900;*,*');
background-size:cover;
height: 100%;
transform:scale(1);
width: 100%;
}
<script src="https://rawgithub.com/soulwire/fit.js/master/fit.js"></script>
<button id="moreZoom">
More Zoom
</button>
<div id="foo">
<div
http://jsfiddle.net/as20h6t4/5/
Related
I trying to create a map framework for some games and i have a problem with recalc position of marker. Look url to test, with wheel you can resize div with image but the dot red not come back to own position. Sorry but im new on this y trying to learn more about js and css. Thanks
$('.map-live').css('width', "928px");
$('.map-live').css('height', "928px");
$('.map-live').css('background-size', "100%");
$('.map-live').bind('mousewheel DOMMouseScroll', function(event) {
var divSize = $('.map-live').css('width');
console.log(divSize);
divSize = divSize.replace('px', '')
divSize = parseInt(divSize);
console.log("oldSize: " + divSize);
var delta_px = event.originalEvent.wheelDelta > 0 ? (divSize + (divSize * 0.15)) : (divSize - (divSize * 0.15));
console.log("NewSize: " + delta_px);
$(this).css('width', delta_px + "px");
$(this).css('height', delta_px + "px");
$(this).css('background-size', "100%");
UpdatePoints();
});
$(function() {
$("#map-live").draggable();
});
document.getElementById('map-live').addEventListener('click', printPosition)
function getPosition(e) {
var rect = e.target.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
return {
x,
y
}
}
function printPosition(e) {
var position = getPosition(e);
console.log('X: ' + position.x + ' Y: ' + position.y);
var divX = parseInt($('.map-live').css('width').replace('px', ''));
var divY = parseInt($('.map-live').css('height').replace('px', ''));
var vhX = (position.x / divX) * 100;
var vhY = (position.y / divY) * 100;
console.log('vhX: ' + vhX + ' vhY: ' + vhY);
}
function UpdatePoints() {
$('.point').css('top', '2.477565353101834vh');
$('.point').css('left', '2.477565353101834vh');
$('.point').css('position', 'absolute');
}
body {
margin: 0;
overflow: hidden;
}
.map-live {
position: absolute;
left: 10px;
z-index: 9;
background-image: url(https://i.ibb.co/d2y5G1y/map.jpg);
width: 222px;
height: 222px;
transition: all 0.2s linear;
}
.point {
position: absolute;
left: 2.477565353101834vh;
top: 2.477565353101834vh;
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="map-live ui-widget-content" id="map-live">
<div class="point"></div>
</div>
jsfiddle.net/f84mto52
Someone can correct me, but I believe your use of position: absolute is what is making the <div class="point"></div> stay in place.
Your UpdatePoints is setting always the same position in the div. With 'vh' you are calculating and absolute position proportional to viewport, no to parent container.
So, you are zooming the background image but the position (x, y) will be always be (x, y), positions are not zoomed. You need to recalculate which is the new position.
So you need to calculate new position.
function UpdatePoints(){
var divW = parseInt($('.map-live').css('width').replace('px',''));
var divH = parseInt($('.map-live').css('height').replace('px',''));
var topPosition = (2.477565353101834 / 928) * divH;
var leftPosition = (2.477565353101834 / 928) * divW;
$('.point').css('top', topPosition+'vh');
$('.point').css('left', leftPosition+'vh');
$('.point').css('position', 'absolute');
}
Also, instead using 'vh' I recommend to calculate the px position instead. I have added the already calculated delta_px parameter to UpdatePoints function:
<style>
.point {
position: absolute;
left: 22.99180647678502px;
top: 22.99180647678502px;
width: 10px;
height: 10px;
background-color: red;
border-radius: 50%;
}
</style>
<script>
function UpdatePoints(delta_px){
var position = (delta_px/100)*2.477565353101834;
$('.point').css('top', position+'px');
$('.point').css('left', position+'px');
$('.point').css('position', 'absolute');
}
</script>
Also, here we are calculating the top-left position of the .point element, not the position for the center. As it is a circle, it work fine, but if you use any other shape the position translation should be calculated from its center.
I recommend to do some research about how to translate elements. You can start here:
Calculating relative position of points when zoomed in and enlarged by a rectangle!
Zoom in on a point (using scale and translate)!
How do I effectively calculate zoom scale?!
I have a parent div that contains an image with a bunch of "holes" in it. I have a child div for each hole that defines the exact size of those holes. In the holes, I have text that I've set to position:absolute so that they fit exactly in the holes. However, when I resize the parent div, the contents don't scale at all and they stay the same size. They're also not inside the holes anymore.
User '%' as a unit instead of pixel
<div id="ParentDiv">
<img src="../610614-spring-forest.jpg">
<div class="hole1">Tree1</div>
</div>
#ParentDiv{
max-width:900px;
position: relative;
}
img{
width: 100%;
height: auto;
}
.hole1{
position: absolute;
left:2.75%;
top:23.87%;
}
You can use Viewport Hieght or Viewport Width unit for that case. Below is the example how you could use.
#ParentDiv{
max-width:100vw;
max-height:100vh;
position: relative;
}
img{
width: 100%;
height: auto;
}
.hole1{
position: absolute;
/*left:2.75%;
top:23.87%;*/
left:2.75vw;
top:23.87vh;
}
Try to use similar, hope you will get the desired result.
You could use a CSS property called transform instead of directly changing the size.
When you need to set the size of the image:
// this is the container the image and its text is in
imageContainer = document.getElementById('myDiv');
// original size of image
origX = 400;
origY = 300;
// size you need it to change to
newX = 800;
newY = 600;
/*
Tells CSS to stretch from the top-left edge of the object, so it won't stretch off the left side of the screen
Best way to change value would be percentages
Value of '0 0' sets origin to top-left
Value of '100% 100%' sets origin to bottom-right
*/
imageContainer.style.transformOrigin = '0 0';
//the following is just one string, broken into multiple lines for easy explanation
// tells CSS that the transform type is scale
imageContainer.style.transform = 'scale(' +
// tells CSS how many times normal size to widen image. in this case evaluates to 2, since 800/400 is 2, making image 2x wider
(newX / origX) + ',' +
// tells CSS how many times normal size to heighten image. in this case evaluates to 2, since 600/300 is 2, making image 2x taller
(newY / origY) + ')';
Assuming you have no major performance-sapping functions, this will work great. It's just a little slow if you have loads of stuff going on.
Uncommented:
imageContainer = document.getElementById('myDiv');
origX = 400;
origY = 300;
newX = 800;
newY = 600;
imageContainer.style.transformOrigin = '0 0';
imageContainer.style.transform = 'scale(' + (newX / origX) + ',' (newY / origY) + ')';
I'm trying to rotate a container with javascript and css property transform and transform-origin, the idea is to rotate it around certain coordinates (For example a pinch gesture center between the two fingers), I'm using this simple code (snippet attached) right now to rotate the container and using the onclick event to capture the anchor point. It is working properly as long as you keep clicking without moving the cursor to a different position on the container. There's an issue when you change the click position once the container has been rotated, the expected behavior is to keep track of the transformation and start rotating for that new point, however right now the container is doing an odd jump. I think that some x,y translation need to be added to the container, but i can figure out what's the correct factor to add to the container.
I'm not sure if I've illustrated well the expected behavior, to make sure here's and example: Imagine you pin a note to a surface at certain position, then, you start rotating the note, having the pin as anchor point. Now, after rotating the note a little, you put out the pin (Keeping the note at the same place), then you place the pin on a different position on the note and rotate again with that new anchor point. That's the expected behavior, hope i have explained myself well.
Here's a snippet to show it better, also available on codepen, cheers.
http://codepen.io/vasilycrespo/pen/GZeYpB
var angle = 15,
scale = 1,
origin = { x: 0, y: 0};
var transform = function (e) {
var map = document.getElementById("map");
angle += 15;
map.style.transformOrigin = e.pageX + "px " + e.pageY + "px";
map.style.transform = "rotate("+angle+"deg) scale("+ scale +")";
};
.content{
position: fixed;
top: 0px;
left: 0px;
margin-top:0;
margin-left:0;
background-color: #ccc;
width: 100%;
height: 100%;
}
.square{
position: absolute;
width: 400px;
height: 400px;
background-image: url(http://www.pnas.org/site/misc/images/15-02545.500.jpg);
background-size: cover;
}
<div class="content" onclick="transform(event)">
<div class="square" id="map"></div>
</div>
The problem is that every time you click, the div changes position based on where you click. After the first click, you should save e.pageX and e.pageY, and in the next clicks you should use the saved values. You can change your transform function to this:
var transform = (function () {
var pageX, pageY;
return function(e) {
if (typeof pageX === "undefined") {
pageX = e.pageX
pageY = e.pageY
}
var map = document.getElementById("map"), xr;
angle += 15;
map.style.transformOrigin = pageX + "px " + pageY + "px";
map.style.transform = "rotate("+angle+"deg) scale("+ scale +")";
}
}())
See updated Code Pen.
I am trying to slide image from left to right and after a set point it should again slide in reverse direction. This is my code somehow its not working as i am going wrong somewhere in the if statement.
(function($) {
var x = 0;
var y = 0;
//cache a reference to the banner
var banner = $("#banner");
// set initial banner background position
banner.css('backgroundPosition', x + 'px' + ' ' + y + 'px');
// scroll up background position every 90 milliseconds
window.setInterval(function() {
banner.css("backgroundPosition", x + 'px' + ' ' + y + 'px');
x++;
//x--;
//if you need to scroll image horizontally -
// uncomment x and comment y
}, 90);
if ($(banner.offset().left > 40) {
banner.css("backgroundPosition", "0px 0px ");
}
})(jQuery);
div#banner {
width: 960px;
height: 200px;
margin: auto;
background: url(http://cdn-careers.sstatic.net/careers/gethired/img/companypageadfallback-leaderboard-2.png?v=59b591051ad7) no-repeat 0 0;
}
div#banner p {
font: 15px Arial, Helvetica, sans-serif;
color: white;
position: relative;
left: 20px;
top: 120px;
width: 305px;
padding: 20px;
background: black;
text-align: center;
text-transform: uppercase;
letter-spacing: 20px;
zoom: 1;
filter: alpha(opacity=50);
opacity: 0.5;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="banner"></div>
Firstly, you are using a IIFE (Immediately Invoked Function Expression) instead of a DOM ready handler. This code will only work if placed after the elements it references.
Use this shortcut for DOM ready that also provides a locally scoped $
jQuery(function ($) {...});
You also have a missing closing paren (or really a redundant $( as it is already a jQuery object):
JSFiddle: http://jsfiddle.net/g0gn4osy/7/
You also need to have a delta value that changes the direction when you hit a bound value. I sped up your timing to show this:
jQuery(function ($) {
var delta = 1;
var y = 0;
//cache a reference to the banner
var $banner = $("#banner");
// set initial banner background position
$banner.css('background-position', '0px' + ' ' + y + 'px');
// scroll up background position every 90 milliseconds
window.setInterval(function () {
var position = parseInt($banner.css('background-position'));
if (position >= 40 || position < 0) {
delta = -delta;
}
position += delta;
$banner.css("background-position", position + 'px' + ' ' + y + 'px');
}, 10);
});
Notes:
You also had backgroundPosition instead of background-position for the CSS property. I prefer to use the values that match the css properties (personal choice only for maintenance).
To avoid the redundant $() issue, I recommend you prefix jQuery variables with $. e.g. $banner in this case. Then it becomes obvious you are dealing with a jQuery object.
I tend to use the current position of an element, rather than keep a global var running. This allows for external influences to change the position and still work. Have removed x and just use position.
Inspired and modelled on Gone Coding's answer.
I have expanded his example to take into account the image width and the view pane DIV width.
It now scrolls to image end and then back. You never scroll off the canvas or past a visible part of the image. It doesn't jerk or rock, just switches direction.
With awareness of the viewing box width you can easily adjust the width of div#banner to fit the display space and the code adjusts. Just remember to set the background image width imgW var.
I have also added:
Visual indicator for testing with a current position and scroll direction. (With -1 is scrolling left, +1 is scrolling right),
Image start position in px. (A minus number or Zero. With 0 is start image at left, Minus number is start image part way through i.e image pre-scrolled left)
Image start vertical position in px (to vertically pull image up/down. Useful if view pane height shorter than image height and you want to tweak what is seen)
Things to do:
Change image URL (background: url(IMAGENAMEHERE) no-repeat 0 0;)
Insert image width (var imgW = #PIXELWIDTH#;)
Play with WIDTH: and HEIGHT: of view pane (div#banner)
Enjoy.
Fiddle
Have a play http://jsfiddle.net/Lm5yk46h/
Image credit Mark Higgins | Dreamstime.com Image source for purchase
Javascript
jQuery(function ($) {
var delta = 1;
var imgW = 3000;//width of image px
var imgY = 0;//to shift image view vertically px (Minus or zero)
//cache ref to #banner
var $banner = $("#banner");
var viewpaneW = $banner.width();
var endpos = (imgW - viewpaneW);
var startpos = 0;//0 or negative number
// set initial banner background position
$banner.css('background-position', startpos + 'px' + ' ' + imgY + 'px');
// scroll background position every 20ms
window.setInterval(function () {
var position = parseInt($banner.css('background-position'));
// minus is left, plus is right
if (position >= 0 ) delta = -delta;//go left
if (position < (-1*endpos)) delta = (-1*delta);//go right
position += delta;//increment posn
$banner.css("background-position", position + 'px' + ' ' + imgY + 'px');
$("#indicator").text('Posn:' + position + ' | direction: ' + delta);
}, 20);
});
CSS
div#canvas {
background-color: #999;
width: 100%;
height: 400px;
margin:0;padding:10px;
}
div#banner {
width: 460px;
height: 300px;
margin: 10px;
background: url(https://digido.net/eg/newcastle-beach-3000x300.jpg) no-repeat 0 0;
}
div#banner p {
font: 13px Arial, Helvetica, sans-serif;
color: white;
position: relative;
left: 0;
top: 310px;
width: 99%;
padding: 10px;
background: black;
text-align: center;
text-transform: uppercase;
letter-spacing: 8px;
zoom: 1;
filter: alpha(opacity=50);
opacity: 0.5;
}
HTML
<div id="canvas">
<div id="banner">
<p id="indicator">Hit run</p>
</div>
</div>
Just put the if condition inside the setInterval. And check the syntax error. The if doesn't have a closing }:
// scroll up background position every 90 milliseconds
window.setInterval(function() {
banner.css("backgroundPosition", x + 'px' + ' ' + y + 'px');
x++;
//x--;
if (banner.offset().left > 40) {
banner.css("backgroundPosition", "0px 0px ");
}
}, 90);
Your "if" should be like this:
if ($(banner).offset().left > 40) {
banner.css("backgroundPosition", "0px 0px ");
}
https://jsfiddle.net/wc4b2g97/
your if should be inserted inside your setInterval handler, so it would get evaluated every 90 milliseconds (thank you for correcting me).
Actually, your if is evaluted only the first time, when your javascript file is parse.
Add it into your setInterval and it should work as expected
I have two divs serving as two panels one to the left and one to the right.
They take 70% and 30% of the area.
I have a separator between them.
When I drag the separator to the left or right, I want that to remain as the position of the separator. i.e., I should be able to dynamically resize the left and right divs by dragging.
Here is the code I have:
http://jsbin.com/witicozi/1/edit
HTML:
<!DOCTYPE html>
<html>
<head>
<body>
<div style='height: 100px'>
<div id='left'>...</div>
<div id='separator'></div>
<div id='right'>...</div>
</div>
</body>
</html>
CSS:
#left {
float: left;
width: 70%;
height: 100%;
overflow: auto;
}
#separator {
float: left;
width: 3px;
height: 100%;
background-color: gray;
cursor: col-resize;
}
#right {
height: 100%;
overflow: auto;
}
JavaScript:
document.querySelector('#separator').addEventListener('drag', function (event) {
var newX = event.clientX;
var totalWidth = document.querySelector('#left').offsetWidth;
document.querySelector('#left').style.width = ((newX / totalWidth) * 100) + '%';
});
The problems:
The resizing happens, but the separator jumps around randomly. It even falls down many times. I have no idea what's happening.
The mouse cursor changes to a hand when the dragging begins. I want it to remain a col-resize.
It is very hard to drag.
No JQuery please.
If you use console.log(event), it shows that event.clientX doesn't return exactly what you are looking for. The following JavaScript worked for me in chrome.
document.getElementById('separator').addEventListener('drag', function(event) {
var left = document.getElementById('left');
var newX = event.offsetX + left.offsetWidth;
left.style.width = newX + 'px';
});
The event.offsetX value that it is returning is the location (in px) of the upper left hand corner of the left div. This will give you the same result but using percentages so that when the resize the window the columns adjust:
document.getElementById('separator').addEventListener('drag', function(event) {
var left = document.getElementById('left');
var newX = event.offsetX + left.offsetWidth;
left.style.width = (newX / window.innerWidth * 100) + '%';
});
Taking a bit of a different approach: rather than using the drag and drop functionality, I used some coupled mouse down and mouse up listeners. This has better cross-browser compatibility (at least as far as my testing goes) and it has the added benefit of being able to easily control the cursor.
var resize = function(event) {
var newX = event.clientX;
document.getElementById('left').style.width = (newX / window.innerWidth * 100) + '%';
};
document.getElementById('separator').addEventListener('mousedown', function(event) {
document.addEventListener('mousemove', resize);
document.body.style.cursor = 'col-resize';
});
document.addEventListener('mouseup', function(event) {
document.removeEventListener('mousemove', resize);
document.body.style.cursor = '';
});