Zoom based on cursor using javascript - javascript

I've both tried to solve the problem as well as search StackOverflow for multiple solutions, none that seemed to work properly. I have what appears to be a close but not quite the end result I'm looking for. I'm trying to make it so when the user zooms using the mousewheel, the zoom being based on the cursor's position.
Could someone explain what I'm doing wrong here. Somewhere in my calculation for the image offset im doing something wrong which you'll see when you test it.
// offset image based on cursor position
var width = img_ele.getBoundingClientRect().width;
var height = img_ele.getBoundingClientRect().height;
var x_cursor = window.event.clientX;
var y_cursor = window.event.clientY;
var x = img_ele.offsetLeft;
var y = img_ele.offsetTop;
// Calculate displacement of zooming position.
var dx = x - ((x_cursor - x) * (factor - 1.0));
var dy = y - ((y_cursor - y) * (factor - 1.0));
img_ele.style.left = dx + 'px';
img_ele.style.top = dy + 'px';
Below is the full code. Just change the src image to one of your liking.
<!DOCTYPE html>
<html>
<body>
<div id="container">
<img ondragstart="return false" id="drag-img" src="map.jpg" />
</div>
<input type="button" id="zoomout" class="button" value="Zoom out">
<input type="button" id="zoomin" class="button" value="Zoom in">
<input type="button" id="zoomfit" class="button" value="Zoom fit">
</body>
</html>
<script>
var img_ele = null,
x_cursor = 0,
y_cursor = 0,
x_img_ele = 0,
y_img_ele = 0;
function zoom(factor) {
img_ele = document.getElementById('drag-img');
// Zoom into the image.
var width = img_ele.getBoundingClientRect().width;
var height = img_ele.getBoundingClientRect().height;
img_ele.style.width = (width * factor) + 'px';
img_ele.style.height = (height * factor) + 'px';
// offset image based on cursor position
var width = img_ele.getBoundingClientRect().width;
var height = img_ele.getBoundingClientRect().height;
var x_cursor = window.event.clientX;
var y_cursor = window.event.clientY;
var x = img_ele.offsetLeft;
var y = img_ele.offsetTop;
// Calculate displacement of zooming position.
var dx = x - ((x_cursor - x) * (factor - 1.0));
var dy = y - ((y_cursor - y) * (factor - 1.0));
img_ele.style.left = dx + 'px';
img_ele.style.top = dy + 'px';
console.log('MAP SIZE : ' + width, height);
console.log('MAP TOP/LEFT : ' + x, y, 'NEW:', dx, dy);
console.log('CURSOR : ' + x_cursor, y_cursor);
img_ele = null;
}
function zoom_fit() {
bb_el = document.getElementById('container')
img_el = document.getElementById('drag-img');
var width = bb_el.getBoundingClientRect().width;
var height = bb_el.getBoundingClientRect().height;
img_el.style.width = width + 'px';
img_el.style.height = height + 'px';
img_el.style.left = '0px';
img_el.style.top = '0px';
img_el = null;
}
document.getElementById('zoomout').addEventListener('click', function() {
zoom(0.9);
});
document.getElementById('zoomin').addEventListener('click', function() {
zoom(1.1);
});
document.getElementById('zoomfit').addEventListener('click', function() {
zoom_fit();
});
document.addEventListener('mousewheel', function(event) {
event.preventDefault();
x_cursor = window.event.clientX;
y_cursor = window.event.clientY;
// console.log('ZOOM : ' + 'X:', x_cursor, 'Y:', y_cursor);
if (event.deltaY < 0) {
// console.log('scrolling up');
zoom(1.1);
}
if (event.deltaY > 0) {
// console.log('scrolling down');
zoom(0.9);
}
});
function start_drag() {
img_ele = this;
// console.log('inside start_drag var img_ele set to : ' + this);
x_img_ele = window.event.clientX - document.getElementById('drag-img').offsetLeft;
y_img_ele = window.event.clientY - document.getElementById('drag-img').offsetTop;
// console.log('start_drag : ' + 'x_img_ele:', x_img_ele, 'y_img_ele:', y_img_ele);
}
function stop_drag() {
// console.log('stop drag');
img_ele = null;
}
function while_drag() {
// console.log('while_drag: ', window.event);
var x_cursor = window.event.clientX;
var y_cursor = window.event.clientY;
if (img_ele !== null) {
img_ele.style.left = (x_cursor - x_img_ele) + 'px';
img_ele.style.top = ( window.event.clientY - y_img_ele) + 'px';
// console.log('while_drag: ','x_cursor', x_cursor, 'x_img_ele', x_img_ele, 'y_cursor', y_cursor, 'y_img_ele', y_img_ele,'Image left and top', img_ele.style.left+' - '+img_ele.style.top);
}
}
document.getElementById('drag-img').addEventListener('mousedown', start_drag);
document.getElementById('container').addEventListener('mousemove', while_drag);
document.getElementById('container').addEventListener('mouseup', stop_drag);
function while_drag() {
var x_cursor = window.event.clientX;
var y_cursor = window.event.clientY;
if (img_ele !== null) {
img_ele.style.left = (x_cursor - x_img_ele) + 'px';
img_ele.style.top = ( window.event.clientY - y_img_ele) + 'px';
// console.log(img_ele.style.left+' - '+img_ele.style.top);
}
}
document.getElementById('drag-img').addEventListener('mousedown', start_drag);
document.getElementById('container').addEventListener('mousemove', while_drag);
document.getElementById('container').addEventListener('mouseup', stop_drag);
</script>
<style>
#drag-img {
cursor: move;
position: relative;
width: 400px;
height: 400px;
}
#container {
overflow: hidden;
background: red;
width: 400px;
height: 400px;
}
.button {
width: 80px;
height: 25px;
}
</style>

Related

Image doesn't render in print preview

I need to print a element, for this, i am using primefaces <p:printer>
In carDetail panelGrid, i have a zoomable image, when i click in print commandlink, the zoomed image does not render in print preview.
zoom JS:
function updateBgStyle() {
if (bgPosX > 0) {
bgPosX = 0;
} else if (bgPosX < width - bgWidth) {
bgPosX = width - bgWidth;
}
if (bgPosY > 0) {
bgPosY = 0;
} else if (bgPosY < height - bgHeight) {
bgPosY = height - bgHeight;
}
img.style.backgroundSize = bgWidth+'px '+bgHeight+'px';
img.style.backgroundPosition = bgPosX+'px '+bgPosY+'px';
x = document.getElementById('myimage');
img2 = document.createElement("IMG");
img2.src = '../../RESOURCES/images/remoteAgent/473_180420160608_HJF4013_2.jpg';
document.getElementById('myresult').style.backgroundSize = img.style.backgroundSize;
document.getElementById('myresult').style.backgroundPosition = img.style.backgroundPosition;
document.getElementById('myresult').style.backgroundImage = "url('" + img2.src + "')";
}
function onwheel(e) {
var deltaY = 0;
e.preventDefault();
if (e.deltaY) {
deltaY = e.deltaY;
} else if (e.wheelDelta) {
deltaY = -e.wheelDelta;
}
var rect = img.getBoundingClientRect();
var offsetX = e.pageX - rect.left - window.pageXOffset;
var offsetY = e.pageY - rect.top - window.pageYOffset;
var bgCursorX = offsetX - bgPosX;
var bgCursorY = offsetY - bgPosY;
var bgRatioX = bgCursorX/bgWidth;
var bgRatioY = bgCursorY/bgHeight;
if (deltaY < 0) {
bgWidth += bgWidth*settings.zoom;
bgHeight += bgHeight*settings.zoom;
} else {
bgWidth -= bgWidth*settings.zoom;
bgHeight -= bgHeight*settings.zoom;
}
if (settings.maxZoom) {
bgWidth = Math.min(width*settings.maxZoom, bgWidth);
bgHeight = Math.min(height*settings.maxZoom, bgHeight);
}
bgPosX = offsetX - (bgWidth * bgRatioX);
bgPosY = offsetY - (bgHeight * bgRatioY);
if (bgWidth <= width || bgHeight <= height) {
reset();
} else {
updateBgStyle();
}
}
xhtml:
<p:panelGrid id="images" columns="1" style="border: 2px solid white;float: right;
border: 2px solid white;">
<script>
wheelzoom(document.querySelector('img.zoom'));
</script>
<img class="zoom" id="myimage" src="../../RESOURCES/images/remoteAgent/473_180420160608_HJF4013_2.jpg"
style=" width: 340px; margin-top: 20px;"/>
<div id="myresult" style="width: 340px;height: 200px; align: center; border: 1px solid black;"></div>
</p:panelGrid>
<p:commandLink style="margin: 2%; width: 15px; height: 15px;">
<h:graphicImage url="/RESOURCES/images/remoteAgent/bolaVerde.png" style="margin: 2%; width: 15px; height: 15px;"/>
<p:printer target=":form:carDetail"/>
</p:commandLink>
The zoomed/non-zoomed image doesn't appear in print preview, but i update the result img
every time the wheel event occurs
Test page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
template="/RESOURCES/template/layoutPrincipal.xhtml">
<ui:define name="head">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<style>
.parrent_ggn{
overflow: hidden;
width: 200px ;
height: 200px;
}
.parrent_ggn img{
width: 100%;
}
</style>
</ui:define>
<ui:define name="cont_principal">
<div class="parrent_ggn" id="parrent_ggn1">
<div>
<img src="https://www.w3schools.com/jsref/img_pulpit.jpg"/>
</div>
</div>
<script>
function ScrollZoom(container,max_scale,factor){
var target = container.children().first()
var size = {w:target.width(),h:target.height()}
var pos = {x:0,y:0}
var zoom_target = {x:0,y:0}
var zoom_point = {x:0,y:0}
var scale = 1
target.css('transform-origin','0 0')
target.on("mousewheel DOMMouseScroll",scrolled)
function scrolled(e){
var offset = container.offset()
zoom_point.x = e.pageX - offset.left
zoom_point.y = e.pageY - offset.top
e.preventDefault();
var delta = e.delta || e.originalEvent.wheelDelta;
if (delta === undefined) {
//we are on firefox
delta = e.originalEvent.detail;
}
delta = Math.max(-1,Math.min(1,delta)) // cap the delta to [-1,1] for cross browser consistency
// determine the point on where the slide is zoomed in
zoom_target.x = (zoom_point.x - pos.x)/scale
zoom_target.y = (zoom_point.y - pos.y)/scale
// apply zoom
scale += delta*factor * scale
scale = Math.max(1,Math.min(max_scale,scale))
// calculate x and y based on zoom
pos.x = -zoom_target.x * scale + zoom_point.x
pos.y = -zoom_target.y * scale + zoom_point.y
// Make sure the slide stays in its container area when zooming out
if(pos.x>0)
pos.x = 0
if(pos.x+size.w*scale<size.w)
pos.x = -size.w*(scale-1)
if(pos.y>0)
pos.y = 0
if(pos.y+size.h*scale<size.h)
pos.y = -size.h*(scale-1)
update()
}
function update(){
target.css('transform','translate('+(pos.x)+'px,'+(pos.y)+'px) scale('+scale+','+scale+')')
}
}
var scroll_zoom = new ScrollZoom($('#parrent_ggn1'),4,0.5);
</script>
</ui:define>
</ui:composition>
By default, a browser will ignore background css rules when printing a page, and you can't overcome this using css.
The user will need to change their browser settings.mor
To keep yourself from relying on that, put the images directly in the HTML with an actual <img /> tag.
you can set parent ‍‌overflow: hidden; and set image transform then increase scale image element for zoomable.this should work in print.
function ScrollZoom(container,max_scale,factor){
var target = container.children().first()
var size = {w:target.width(),h:target.height()}
var pos = {x:0,y:0}
var zoom_target = {x:0,y:0}
var zoom_point = {x:0,y:0}
var scale = 1
target.css('transform-origin','0 0')
target.on("mousewheel DOMMouseScroll",scrolled)
function scrolled(e){
var offset = container.offset()
zoom_point.x = e.pageX - offset.left
zoom_point.y = e.pageY - offset.top
e.preventDefault();
var delta = e.delta || e.originalEvent.wheelDelta;
if (delta === undefined) {
//we are on firefox
delta = e.originalEvent.detail;
}
delta = Math.max(-1,Math.min(1,delta)) // cap the delta to [-1,1] for cross browser consistency
// determine the point on where the slide is zoomed in
zoom_target.x = (zoom_point.x - pos.x)/scale
zoom_target.y = (zoom_point.y - pos.y)/scale
// apply zoom
scale += delta*factor * scale
scale = Math.max(1,Math.min(max_scale,scale))
// calculate x and y based on zoom
pos.x = -zoom_target.x * scale + zoom_point.x
pos.y = -zoom_target.y * scale + zoom_point.y
// Make sure the slide stays in its container area when zooming out
if(pos.x>0)
pos.x = 0
if(pos.x+size.w*scale<size.w)
pos.x = -size.w*(scale-1)
if(pos.y>0)
pos.y = 0
if(pos.y+size.h*scale<size.h)
pos.y = -size.h*(scale-1)
update()
}
function update(){
target.css('transform','translate('+(pos.x)+'px,'+(pos.y)+'px) scale('+scale+','+scale+')')
}
}
var scroll_zoom = new ScrollZoom($('#parrent_ggn1'),4,0.5);
.parrent_ggn{
overflow: hidden;
width: 200px ;
height: 200px;
}
.parrent_ggn img{
width: 100%;
}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<div class="parrent_ggn" id="parrent_ggn1">
<div>
<img src="https://www.w3schools.com/jsref/img_pulpit.jpg">
</div>
</div>

how to make a div follow cursor inside another div, on mousemove with pure JS

I'm a beginner when it comes to pure Javascript. I would like to create an effect such as this one created with jquery:
var mouseX = 0, mouseY = 0, limitX, limitY, containerWidth;
$(document).ready(function() {
//Declaring the container size variable when we dom is ready
//Grabbing the size of an element gives a number no longer a percentage
containerWidth = $(".container").width();
containerHeight = $(".container").height();
$("#debug").html('Container Width = ' + containerWidth + '<br/>Container Height = ' + containerHeight);
// cache the selector
var follower = $("#follower");
var xp = 0, yp = 0;
// limitX is now the difference between the #container's width (=80%) and 15px
limitX = containerWidth-15;
limitY = containerHeight-15;
var loop = setInterval(function(){
// change 12 to alter damping higher is slower
xp += (mouseX - xp) / 6;
yp += (mouseY - yp) / 6;
follower.css({left:xp, top:yp});
}, 15);
//Since changing the window size affects the width, we need to redefine the container size variable so that's it's current
$(window).resize(function() {
//this makes limiX change based on container width
limitX = $(".container").width()-15;
$("#debug").html('Container Width = ' + containerWidth + '<br/>Container Height = ' + containerHeight);
}).resize();
$(document).on('mousemove', function (e) {
mouseX = Math.min(e.pageX, limitX);
mouseY = Math.min(e.pageY, limitY);
});
});
link to user's fiddle : http://jsfiddle.net/alexchopjian/5QfYL/5/,
but using pure Javascript. Is it possible?
I will be very grateful for any clues as how to get at this.
This is not the exact copy but it is a starting point:
var mouseX = 0, mouseY = 0, limitX, limitY, containerWidth;
window.onload = function(e) {
var containerObjStyle = window.getComputedStyle(document.querySelectorAll(".container")[0]);
containerWidth = parseFloat(containerObjStyle.width).toFixed(0);
containerHeight = parseFloat(containerObjStyle.height).toFixed(0);
document.getElementById('debug').innerHTML = 'Container Width = ' + containerWidth + '<br/>Container Height = ' + containerHeight;
var follower = document.getElementById("follower");
var xp = 0, yp = 0;
limitX = containerWidth-15;
limitY = containerHeight-15;
var loop = setInterval(function(){
xp = (mouseX == limitX) ? limitX : mouseX -7;
xp = (xp < 0) ? 0 : xp;
yp = (mouseY == limitY) ? limitY : mouseY -7;
yp = (yp < 0) ? 0 : yp;
follower.style.left = xp + 'px';
follower.style.top = yp + 'px';
}, 15);
window.onresize = function(e) {
limitX = parseFloat(window.getComputedStyle(document.querySelectorAll(".container")[0]).width).toFixed(0);
document.getElementById("debug")[0].innerHTML='Container Width = ' + containerWidth + '<br/>Container Height = ' + containerHeight;
}
document.onmousemove = function(e) {
mouseX = Math.min(e.pageX, limitX);
mouseY = Math.min(e.pageY, limitY);
}
};
#follower{
position : relative;
background-color : yellow;
width:15px;
height:15px;
border-radius:50px;
}
.container {
width:80%;
height:150px;
position:absolute;
top:0;
left:0;
overflow:hidden;
border:1px solid #000000;
}
<p id="debug"></p>
<div class="container">
<div id="follower"></div>
</div>

How to snap elements to other draggable elements using interact.js

I'm making a draggable elements using interactjs.io
I need implement exactly the same behaviour that jQuery UI snap. You can see an example here in the official documentation:
The behaviour is: snaps to all other draggable elements
In interactjs.io, in the documentation, you have "Snapping" (link documentation), but I don't find the way of coding it.
I have created a fiddle here: Fiddle Link
This is my JS Code:
interact('.draggable')
.draggable({
onmove: dragMoveListener,
snap: {},
});
function dragMoveListener (event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// update the position attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
I need modify the snap section code, to make the draggable items snapping with others.
snap: {}
Thanks!!
The following code can give you some ideas to get the result that you want. It works with draggable elements of different sizes. Function targets are used to set the target points and lines.
You can test it in this jsfiddle.
var AXIS_RANGE = 12;
var CORNER_RANGE = 14;
var CORNER_EXCLUDE_AXIS = 8;
var AXIS_EXTRA_RANGE = -6;
var myItems = [];
var currentElement = null;
var offX1, offY1, offX2, offY2;
function getPosition(element) {
return {
x: parseFloat(element.getAttribute('data-x')) || 0,
y: parseFloat(element.getAttribute('data-y')) || 0
};
}
function isBetween(value, min, length) {
return min - AXIS_EXTRA_RANGE < value && value < (min + length) + AXIS_EXTRA_RANGE;
}
function getDistance(value1, value2) {
return Math.abs(value1 - value2);
}
function getSnapCoords(element, axis) {
var result = {
isOK: false
};
if (currentElement && currentElement !== element) {
var pos = getPosition(element);
var cur = getPosition(currentElement);
var distX1a = getDistance(pos.x, cur.x);
var distX1b = getDistance(pos.x, cur.x + currentElement.offsetWidth);
var distX2a = getDistance(pos.x + element.offsetWidth, cur.x);
var distX2b = getDistance(pos.x + element.offsetWidth, cur.x + currentElement.offsetWidth);
var distY1a = getDistance(pos.y, cur.y);
var distY1b = getDistance(pos.y, cur.y + currentElement.offsetHeight);
var distY2a = getDistance(pos.y + element.offsetHeight, cur.y);
var distY2b = getDistance(pos.y + element.offsetHeight, cur.y + currentElement.offsetHeight);
var distXa = Math.min(distX1a, distX2a);
var distXb = Math.min(distX1b, distX2b);
var distYa = Math.min(distY1a, distY2a);
var distYb = Math.min(distY1b, distY2b);
if (distXa < distXb) {
result.offX = offX1;
} else {
result.offX = offX2
}
if (distYa < distYb) {
result.offY = offY1;
} else {
result.offY = offY2
}
var distX1 = Math.min(distX1a, distX1b);
var distX2 = Math.min(distX2a, distX2b);
var distY1 = Math.min(distY1a, distY1b);
var distY2 = Math.min(distY2a, distY2b);
var distX = Math.min(distX1, distX2);
var distY = Math.min(distY1, distY2);
var dist = Math.max(distX, distY);
var acceptAxis = dist > CORNER_EXCLUDE_AXIS;
result.x = distX1 < distX2 ? pos.x : pos.x + element.offsetWidth;
result.y = distY1 < distY2 ? pos.y : pos.y + element.offsetHeight;
var inRangeX1 = isBetween(pos.x, cur.x, currentElement.offsetWidth);
var inRangeX2 = isBetween(cur.x, pos.x, element.offsetWidth);
var inRangeY1 = isBetween(pos.y, cur.y, currentElement.offsetHeight);
var inRangeY2 = isBetween(cur.y, pos.y, element.offsetHeight);
switch (axis) {
case "x":
result.isOK = acceptAxis && (inRangeY1 || inRangeY2);
break;
case "y":
result.isOK = acceptAxis && (inRangeX1 || inRangeX2);
break;
default:
result.isOK = true;
break;
}
}
return result;
}
$('.draggable').each(function() {
var pos = getPosition(this);
this.style.transform = 'translate(' + pos.x + 'px, ' + pos.y + 'px)';
myItems.push(getPosition(this));
});
interact('.draggable').draggable({
onstart: function(event) {
currentElement = event.target;
var pos = getPosition(currentElement);
offX1 = event.clientX - pos.x;
offY1 = event.clientY - pos.y;
offX2 = event.clientX - currentElement.offsetWidth - pos.x;
offY2 = event.clientY - currentElement.offsetHeight - pos.y;
},
onmove: dragMoveListener,
snap: {
targets:
(function() {
var snapPoints = [];
$('.draggable').each(function() {
(function(element) {
// Slide along the X axis
snapPoints.push(
function(x, y) {
var data = getSnapCoords(element, "x");
if (data.isOK) {
return {
x: data.x + data.offX,
range: AXIS_RANGE
};
}
});
// Slide along the Y axis
snapPoints.push(
function(x, y) {
var data = getSnapCoords(element, "y");
if (data.isOK) {
return {
y: data.y + data.offY,
range: AXIS_RANGE
};
}
});
// Snap to corner
snapPoints.push(
function(x, y) {
var data = getSnapCoords(element);
if (data.isOK) {
return {
x: data.x + data.offX,
y: data.y + data.offY,
range: CORNER_RANGE
};
}
});
})(this);
});
return snapPoints;
})()
},
onend: function(event) {
$('.draggable').each(function() {
currentElement = null;
myItems.push(getPosition(this));
});
}
});
function dragMoveListener(event) {
var target = event.target;
var oldPos = getPosition(target);
var x = oldPos.x + event.dx;
var y = oldPos.y + event.dy;
// keep the dragged position in the data-x/data-y attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
$('#position').text('x: ' + x + ' - y: ' + y);
var result = $.grep(myItems, function(e) {
if (e.x == parseInt(target.getAttribute('data-x')) || e.y == parseInt(target.getAttribute('data-y')))
return 1;
});
if (result.length >= 1)
target.style.backgroundColor = '#CCC';
else
target.style.backgroundColor = '#FFF';
}
I made a JSFiddle without using interact.js. I only used jQuery. I did not use interactjs.io as you implied that you only prefer it but don't require it.
The code works with elements of different sizes.
jQuery.fn.reverse = [].reverse;
/* Handle add button clicks*/
$(".add-draggable").click(function() {
var newDraggable = jQuery("<div class='draggable'></div>");
newDraggable.css({
position: 'absolute',
left: 150,
top: 150
})
newDraggable.attr({
'data-x': 150,
'data-y': 150
}).addClass("large");
jQuery(".draggable-wapper").append(newDraggable)
});
// initiate blocks
// This is done in revers as when the element is absolutly positioned .poisition() will retrun differnt values for the next element (mostly x will be 0 for all elements)
$(".draggable").reverse().each(function(i, e) {
_this = jQuery(this);
position = _this.position();
_this.css({
position: 'absolute',
left: position.left,
top: position.top
}).attr("data-y", position.top).attr("data-x", position.left);
});
// Set some variabkles
// Used to differentiate clicks on elements from dragging
var isDragging = false;
// Store coordiators of all elements
var coord;
// The moving element
var element = null;
// The offset to which the moving element snaps to the target element
// in percentage
var snappingYOffset = 20;
var snappingXOffset = 20;
$(".draggable-wapper").on("mousedown", ".draggable", function() {
_this = element = jQuery(this);
coord = [];
isDragging = true;
// Update coord
jQuery(".draggable").each(function(i, e) {
if (i == element.index())
return true;
ele = jQuery(e);
var position = ele.position();
var elementData = getData(ele);
coord[i] = {
leftX: position.left,
rightX: position.left + ele.outerWidth(),
topY: position.top,
bottomY: position.top + ele.outerHeight()
}
jQuery.extend(coord[i], elementData);
});
_this.removeData("last-position");
});
jQuery(document).on("mousemove", function(e) {
if (!isDragging)
return;
var lastPosition = _this.data("last-position");
element.addClass("moving");
if (typeof lastPosition != 'undefined') {
// get difference to detemine new position
var xDelta = e.clientX - lastPosition.x;
var yDelta = e.clientY - lastPosition.y;
var elementX = parseInt(element.attr("data-x"));
var elementY = parseInt(element.attr("data-y"));
element.attr({
"data-x": elementX + xDelta,
"data-y": elementY + yDelta
}).css({
"left": elementX + xDelta,
"top": elementY + yDelta
});
// find which element is closer to moving elements and within offset limits
filterArray(coord, _this);
}
// Save values for next itertation
var position = {
x: e.clientX,
y: e.clientY
};
element.data("last-position", position);
})
.on("mouseup", function() {
if (isDragging) {
isDragging = false;
element.removeClass("moving");
}
});
function filterArray(array, element) {
// Set coord for moving element
// x1: left, x2: right, y1: top, y2: bottom
var elementX1 = parseInt(element.attr("data-x"));
var elementX2 = elementX1 + element.outerWidth();
var elementY1 = parseInt(element.attr("data-y"));
var elementY2 = elementY1 + element.outerHeight();
// Show value inside element
element.html('y:' + elementY1 + '<br> x: ' + elementX1);
var result = {};
// Loop through other elements and match the closeset
array.forEach(function(value, index, originalArray) {
// Get coordinators of each element
// x1: left, x2: right, y1: top, y2: bottom
var x1 = value['leftX'];
var x2 = value['rightX'];
var y1 = value['topY'];
var y2 = value['bottomY'];
// Get which element is bigger; the moving or the target element
var biggerDim = bigger(element, {
height: value['height'],
width: value['width']
});
// Show values inside element
jQuery(".draggable").eq(index).html('y:' + y1 + '<br> x: ' + x1);
// Get offset for partiuclar element
var xOffset = value['xOffset'];
var yOffset = value['yOffset'];
// yRange checks if moving element is moving within the Y range of target element
// This requried to snap if true
var yRange = (biggerDim.height == 'moving') ? y1 >= (elementY1 - yOffset) && y2 <= (elementY2 + yOffset) : elementY1 > (y1 - yOffset) && elementY2 < (y2 + yOffset);
// xRange checks if moving element is moving within the X range of target element
// This requried to snap if true
var xRange = (biggerDim.width == 'moving') ? x1 > (elementX1 - xOffset) && x2 < (elementX2 + xOffset) : elementX1 > (x1 - xOffset) && elementX2 < (x2 + xOffset);
// Is source element (moving) within the Y range
if (yRange) {
// Is source element within right range of target
if (elementX1 >= (x2 - xOffset) && elementX1 <= (x2 + xOffset)) {
// Left side of the moving element
element.css({
"left": x2
});
// Is source element within left range of target
} else if (elementX2 >= (x1 - xOffset) && elementX2 <= (x1 + xOffset)) {
// right side of the moving element
element.css({
"left": x1 - element.outerWidth()
});
}
}
// Is source element (moving) within the X range of target
if (xRange) {
if (elementY1 >= (y2 - yOffset) && elementY1 <= (y2 + yOffset)) {
// Top side of the moving element
element.css({
"top": y2
});
} else if (elementY2 >= (y1 - yOffset) && elementY2 <= (y1 + yOffset)) {
// bottom side of the moving element
element.css({
"top": y1 - element.outerHeight()
});
}
}
});
}
/* Find which element is bigger */
function bigger(moving, target) {
var width1 = moving.outerWidth();
var height1 = moving.outerHeight();
var width2 = target.width;
var height2 = target.height;
var result = {
width: 'target',
height: 'target'
};
if (width1 > width2)
result.width = 'moving';
if (height1 > height2)
result.height = 'moving';
return result;
}
/* Get data releted to a certain element */
function getData(ele) {
var height = ele.outerHeight();
var width = ele.outerWidth();
var xOffset = (width * snappingXOffset) / 100;
var yOffset = (height * snappingYOffset) / 100;
return {
height: height,
width: width,
xOffset: xOffset,
yOffset: yOffset
}
}
.draggable {
background-color: green;
border: 1px solid white;
box-sizing: border-box;
cursor: move;
float: left;
padding: 5px;
position: relative;
color: white;
font-family: "calibri", -webkit-touch-callout: none;
/* iOS Safari */
-webkit-user-select: none;
/* Chrome/Safari/Opera */
-khtml-user-select: none;
/* Konqueror */
-moz-user-select: none;
/* Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */
user-select: none;
/* Non-prefixed version, currently
not supported by any browser */
}
.draggable.large {
height: 300px;
width: 100px;
font-size: 16px;
}
.draggable.small {
height: 50px;
width: 50px;
font-size: 12px;
}
.draggable.medium {
height: 100px;
width: 80px;
font-size: 12px;
}
.draggable-wapper {
float: left;
position: relative;
}
.moving {
z-index: 2;
background-color: purple;
}
.add-draggable {
background-color: green;
border: 1px solid #0a5e1d;
border-radius: 5px;
color: white;
cursor: pointer;
font-size: 19px;
padding: 10px 20px;
position: absolute;
right: 15px;
top: 15px;
transition: all 0.5s ease 0s;
font-family: "calibri",
}
.add-draggable:hover {
opacity: 0.9;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='draggable-wapper'>
<div class='draggable small'></div>
<div class='draggable large'></div>
<div class='draggable large'></div>
<div class='draggable large'></div>
<div class='draggable small'></div>
<div class='draggable medium'></div>
<div class='draggable medium'></div>
</div>
<div class='add-draggable'>
Add
</div>

Pinch to zoom with Hammer.js

I want a pinch to Zoom function for an image. I want it to zoom in the area where the fingers are.
My index is only
<div id="wrapper" style="-webkit-transform: translate3d(0,0,0);overflow: hidden;">
</div>
And my script for zooming and scrolling is similar with this example. I have made a few changes to fit with my project
My problem is in
case 'transform':
rotation = last_rotation + ev.gesture.rotation;
scale = Math.max(1, Math.min(last_scale * ev.gesture.scale, 10));
break;
How can I change it so that it doesn't zoom into the center of the picture but at place where the first finger have touch the display?
Sorry for my bad english :)
This is an example with hammer.js and tap. As you tap it will zoom in at the point where you tapped. The event data is common for all gestures so switching from tap to pinch should work. It is a good example to work on. You may need to increase the scale step as you pinch. It has been tested on chrome(v30) and firefox (v24).
It is based on the solution mentioned at the thread,
Zoom in on a point (using scale and translate)
as you will see an alternative could also be to use canvas.
HTML
<div style="-webkit-transform: translate3d(0,0,0);overflow: hidden;" class="zoomable">
<img src="http://i.telegraph.co.uk/multimedia/archive/01842/landscape-rainbow_1842437i.jpg" />
</div>
JS
(function ($) {
$(document).ready(function () {
var scale = 1; // scale of the image
var xLast = 0; // last x location on the screen
var yLast = 0; // last y location on the screen
var xImage = 0; // last x location on the image
var yImage = 0; // last y location on the image
Hammer($('.zoomable img').get(0)).on("tap", function (event) {
var posX = event.gesture.center.pageX;
var posY = event.gesture.center.pageY;
// find current location on screen
var xScreen = posX; //- $(this).offset().left;
var yScreen = posY; //- $(this).offset().top;
// find current location on the image at the current scale
xImage = xImage + ((xScreen - xLast) / scale);
yImage = yImage + ((yScreen - yLast) / scale);
scale++;
// determine the location on the screen at the new scale
var xNew = (xScreen - xImage) / scale;
var yNew = (yScreen - yImage) / scale;
// save the current screen location
xLast = xScreen;
yLast = yScreen;
// redraw
$(this).css('-webkit-transform', 'scale(' + scale + ')' + 'translate(' + xNew + 'px, ' + yNew + 'px' + ')')
.css('-webkit-transform-origin', xImage + 'px ' + yImage + 'px').css('-moz-transform', 'scale(' + scale + ') translate(' + xNew + 'px, ' + yNew + 'px)').css('-moz-transform-origin', xImage + 'px ' + yImage + 'px')
.css('-o-transform', 'scale(' + scale + ') translate(' + xNew + 'px, ' + yNew + 'px)').css('-o-transform-origin', xImage + 'px ' + yImage + 'px').css('transform', 'scale(' + scale + ') translate(' + xNew + 'px, ' + yNew + 'px)');
});
});
})(jQuery);
http://jsfiddle.net/SySZL/
Check out the Pinch Zoom and Pan with HammerJS demo. This example has been tested on Android, iOS and Windows Phone.
You can find the source code at Pinch Zoom and Pan with HammerJS.
For your convenience, here is the source code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport"
content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<title>Pinch Zoom</title>
</head>
<body>
<div>
<div style="height:150px;background-color:#eeeeee">
Ignore this area. Space is needed to test on the iPhone simulator as pinch simulation on the
iPhone simulator requires the target to be near the middle of the screen and we only respect
touch events in the image area. This space is not needed in production.
</div>
<style>
.pinch-zoom-container {
overflow: hidden;
height: 300px;
}
.pinch-zoom-image {
width: 100%;
}
</style>
<script src="https://hammerjs.github.io/dist/hammer.js"></script>
<script>
var MIN_SCALE = 1; // 1=scaling when first loaded
var MAX_SCALE = 64;
// HammerJS fires "pinch" and "pan" events that are cumulative in nature and not
// deltas. Therefore, we need to store the "last" values of scale, x and y so that we can
// adjust the UI accordingly. It isn't until the "pinchend" and "panend" events are received
// that we can set the "last" values.
// Our "raw" coordinates are not scaled. This allows us to only have to modify our stored
// coordinates when the UI is updated. It also simplifies our calculations as these
// coordinates are without respect to the current scale.
var imgWidth = null;
var imgHeight = null;
var viewportWidth = null;
var viewportHeight = null;
var scale = null;
var lastScale = null;
var container = null;
var img = null;
var x = 0;
var lastX = 0;
var y = 0;
var lastY = 0;
var pinchCenter = null;
// We need to disable the following event handlers so that the browser doesn't try to
// automatically handle our image drag gestures.
var disableImgEventHandlers = function () {
var events = ['onclick', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover',
'onmouseup', 'ondblclick', 'onfocus', 'onblur'];
events.forEach(function (event) {
img[event] = function () {
return false;
};
});
};
// Traverse the DOM to calculate the absolute position of an element
var absolutePosition = function (el) {
var x = 0,
y = 0;
while (el !== null) {
x += el.offsetLeft;
y += el.offsetTop;
el = el.offsetParent;
}
return { x: x, y: y };
};
var restrictScale = function (scale) {
if (scale < MIN_SCALE) {
scale = MIN_SCALE;
} else if (scale > MAX_SCALE) {
scale = MAX_SCALE;
}
return scale;
};
var restrictRawPos = function (pos, viewportDim, imgDim) {
if (pos < viewportDim/scale - imgDim) { // too far left/up?
pos = viewportDim/scale - imgDim;
} else if (pos > 0) { // too far right/down?
pos = 0;
}
return pos;
};
var updateLastPos = function (deltaX, deltaY) {
lastX = x;
lastY = y;
};
var translate = function (deltaX, deltaY) {
// We restrict to the min of the viewport width/height or current width/height as the
// current width/height may be smaller than the viewport width/height
var newX = restrictRawPos(lastX + deltaX/scale,
Math.min(viewportWidth, curWidth), imgWidth);
x = newX;
img.style.marginLeft = Math.ceil(newX*scale) + 'px';
var newY = restrictRawPos(lastY + deltaY/scale,
Math.min(viewportHeight, curHeight), imgHeight);
y = newY;
img.style.marginTop = Math.ceil(newY*scale) + 'px';
};
var zoom = function (scaleBy) {
scale = restrictScale(lastScale*scaleBy);
curWidth = imgWidth*scale;
curHeight = imgHeight*scale;
img.style.width = Math.ceil(curWidth) + 'px';
img.style.height = Math.ceil(curHeight) + 'px';
// Adjust margins to make sure that we aren't out of bounds
translate(0, 0);
};
var rawCenter = function (e) {
var pos = absolutePosition(container);
// We need to account for the scroll position
var scrollLeft = window.pageXOffset ? window.pageXOffset : document.body.scrollLeft;
var scrollTop = window.pageYOffset ? window.pageYOffset : document.body.scrollTop;
var zoomX = -x + (e.center.x - pos.x + scrollLeft)/scale;
var zoomY = -y + (e.center.y - pos.y + scrollTop)/scale;
return { x: zoomX, y: zoomY };
};
var updateLastScale = function () {
lastScale = scale;
};
var zoomAround = function (scaleBy, rawZoomX, rawZoomY, doNotUpdateLast) {
// Zoom
zoom(scaleBy);
// New raw center of viewport
var rawCenterX = -x + Math.min(viewportWidth, curWidth)/2/scale;
var rawCenterY = -y + Math.min(viewportHeight, curHeight)/2/scale;
// Delta
var deltaX = (rawCenterX - rawZoomX)*scale;
var deltaY = (rawCenterY - rawZoomY)*scale;
// Translate back to zoom center
translate(deltaX, deltaY);
if (!doNotUpdateLast) {
updateLastScale();
updateLastPos();
}
};
var zoomCenter = function (scaleBy) {
// Center of viewport
var zoomX = -x + Math.min(viewportWidth, curWidth)/2/scale;
var zoomY = -y + Math.min(viewportHeight, curHeight)/2/scale;
zoomAround(scaleBy, zoomX, zoomY);
};
var zoomIn = function () {
zoomCenter(2);
};
var zoomOut = function () {
zoomCenter(1/2);
};
var onLoad = function () {
img = document.getElementById('pinch-zoom-image-id');
container = img.parentElement;
disableImgEventHandlers();
imgWidth = img.width;
imgHeight = img.height;
viewportWidth = img.offsetWidth;
scale = viewportWidth/imgWidth;
lastScale = scale;
viewportHeight = img.parentElement.offsetHeight;
curWidth = imgWidth*scale;
curHeight = imgHeight*scale;
var hammer = new Hammer(container, {
domEvents: true
});
hammer.get('pinch').set({
enable: true
});
hammer.on('pan', function (e) {
translate(e.deltaX, e.deltaY);
});
hammer.on('panend', function (e) {
updateLastPos();
});
hammer.on('pinch', function (e) {
// We only calculate the pinch center on the first pinch event as we want the center to
// stay consistent during the entire pinch
if (pinchCenter === null) {
pinchCenter = rawCenter(e);
var offsetX = pinchCenter.x*scale - (-x*scale + Math.min(viewportWidth, curWidth)/2);
var offsetY = pinchCenter.y*scale - (-y*scale + Math.min(viewportHeight, curHeight)/2);
pinchCenterOffset = { x: offsetX, y: offsetY };
}
// When the user pinch zooms, she/he expects the pinch center to remain in the same
// relative location of the screen. To achieve this, the raw zoom center is calculated by
// first storing the pinch center and the scaled offset to the current center of the
// image. The new scale is then used to calculate the zoom center. This has the effect of
// actually translating the zoom center on each pinch zoom event.
var newScale = restrictScale(scale*e.scale);
var zoomX = pinchCenter.x*newScale - pinchCenterOffset.x;
var zoomY = pinchCenter.y*newScale - pinchCenterOffset.y;
var zoomCenter = { x: zoomX/newScale, y: zoomY/newScale };
zoomAround(e.scale, zoomCenter.x, zoomCenter.y, true);
});
hammer.on('pinchend', function (e) {
updateLastScale();
updateLastPos();
pinchCenter = null;
});
hammer.on('doubletap', function (e) {
var c = rawCenter(e);
zoomAround(2, c.x, c.y);
});
};
</script>
<button onclick="zoomIn()">Zoom In</button>
<button onclick="zoomOut()">Zoom Out</button>
<div class="pinch-zoom-container">
<img id="pinch-zoom-image-id" class="pinch-zoom-image" onload="onLoad()"
src="https://hammerjs.github.io/assets/img/pano-1.jpg">
</div>
</div>
</body>
</html>

moving background with parallax

I am making a webpage that uses layers with a bit of parallax scrolling. I had this working. Then I don't know what happened because it stopped working. Any help would be appreciated.
Here is the code.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> 'Test'</title>
<link rel="stylesheet" href="/css/21.css">
<script src="/js/21.js" type="text/javascript"></script>
</head>
<body>
<div id="parallax"></div>
<script>
document.addEventListener("DOMContentLoaded", function(){ initParallax(); });
</script>
</body>
</html>
And Javascript
var initParallax = function() {
// Setup variables
var el = document.getElementById("parallax");
var layerDistanceToHorizon = [50, 30, 10, 5];
var horizonDistance = 200;
// Simplified ways to get the background size (we should use all of them in our calculation)
var style = window.getComputedStyle(el, null);
var backgroundSize = style.getPropertyValue("background-size")
.split(",")[0].split(" ")
.map(function(x) {
return parseInt(x)
});
var backgroundOffset = style.getPropertyValue("background-position")
.split(",")[0].split(" ")
.map(function(x) {
return parseInt(x)
});
// The original viewer offset (set to the center of the element here.)
var viewerOffset = [el.offsetWidth / 2, el.offsetHeight / 2];
// Determine the offsets of the element for the mouse-cursor
// coordinates
elOffsets = Utility.getPosition(el);
// Function : Calculate all new offsets according to the viewer x/y
var calculateOffsets = function(x, y) {
var xTan = -1 * x / horizonDistance;
var yTan = -1 * y / horizonDistance;
return layerDistanceToHorizon.map(function(value) {
return [value * xTan, value * yTan];
});
};
// Function : Actually move the viewer
var moveViewer = function(x, y) {
var offsets = calculateOffsets(x, y);
el.style.backgroundPosition = offsets.map(function(off) {
var x = backgroundOffset[0] - off[0];
var y = backgroundOffset[1] - off[1];
return x + "px " + y + "px";
}).join(", ");
};
// Add the mouse-move event
document.addEventListener("mousemove", function(e) {
var mouse = getEventMousePosition(e);
moveViewer(mouse[0] - (elOffsets[0] + viewerOffset[0]), mouse[1] - (elOffsets[1] + viewerOffset[1]));
});
};
// Get the mouse coordinates from an event
var getEventMousePosition = function(e) {
var x = 0;
var y = 0;
if (!e) var e = window.event;
if (e.pageX || e.pageY) {
x = e.pageX;
y = e.pageY;
} else if (e.clientX || e.clientY) {
x = e.clientX + document.body.scrollLeft;
y = e.clientY + document.body.scrollTop;
}
return [x, y];
}

Categories

Resources