How can I keep image and lens rotation synchronized with BlowupJS? - javascript

I used the blowup.js plugin as a base, and I am trying to rotate the image, and the lens to follow the rotation. But it is not working.
When I put the rotate(180deg) for example, the lens and the image are mismatched, if I remove the rotate(180deg) they are aligned.
Anybody know how to help me?
sample in JSFiddle
var $element = $('#target');
$element.css({
'transform': 'rotate(180deg)'
}); // rotate imagem in html
// Constants
var $IMAGE_URL = $element.attr("src");
var NATIVE_IMG = new Image();
NATIVE_IMG.src = $element.attr("src");
var lens = document.createElement("div");
lens.id = "BlowupLens";
$("body").append(lens);
$blowupLens = $("#BlowupLens");
$blowupLens.css({
"position": "absolute",
"display": "none",
"pointer-events": "none",
"zIndex": 999999,
"width": 200,
"height": 200,
"border": "6px solid #FFF",
"background": "#FFF",
"border-radius": "50%",
"box-shadow": "0 8px 17px 0 rgba(0, 0, 0, 0.2)",
"background-repeat": "no-repeat",
});
// Show magnification lens
$element.mouseenter(function() {
$blowupLens.css("display", "block");
});
// Mouse motion on image
$element.mousemove(function(e) {
// Lens position coordinates
var lensX = e.pageX - (200 / 2);
var lensY = e.pageY - (200 / 2);
var width = $element.width();
var height = $element.height();
// Relative coordinates of image
var relX = e.pageX - $('#target').offset().left;
var relY = e.pageY - $('#target').offset().top;
// Zoomed image coordinates
var zoomX = -Math.floor(relX / width * (NATIVE_IMG.width) - 200 / 2);
var zoomY = -Math.floor(relY / height * (NATIVE_IMG.height) - 200 / 2);
var backPos = zoomX + "px " + zoomY + "px";
var backgroundSize = NATIVE_IMG.width + "px " + NATIVE_IMG.height + "px";
// Apply styles to lens
$blowupLens.css({
left: lensX,
top: lensY,
"background-image": "url(" + encodeURI($IMAGE_URL) + ")",
"background-size": backgroundSize,
"background-position": backPos,
"transform": "rotate(180deg)" //rotate the image original
});
})
// Hide magnification lens
$element.mouseleave(function() {
$blowupLens.css("display", "none");
});
#target {
margin-left: 160px;
width: 700;
height: 500px;
}
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<img id="target" src="https://iili.io/0hL7ou.png">
</body>

You might rotate the lens in the opposite direction (-180deg) and inverse background position too:
Side note: you don't want to apply background-image on every mousemove, move it to the lens init.
var $element = $('#target');
$element.css({
'transform': 'rotate(180deg)'
}); // rotate imagem in html
// Constants
var $IMAGE_URL = $element.attr("src");
var NATIVE_IMG = new Image();
NATIVE_IMG.src = $element.attr("src");
var lens = document.createElement("div");
lens.id = "BlowupLens";
$("body").append(lens);
$blowupLens = $("#BlowupLens");
$blowupLens.css({
"position": "absolute",
"display": "none",
"pointer-events": "none",
"zIndex": 999999,
"width": 200,
"height": 200,
"border": "6px solid #FFF",
"background": "#FFF",
"border-radius": "50%",
"box-shadow": "0 8px 17px 0 rgba(0, 0, 0, 0.2)",
"background-repeat": "no-repeat",
});
// Show magnification lens
$element.mouseenter(function() {
$blowupLens.css("display", "block");
});
// Mouse motion on image
$element.mousemove(function(e) {
// Lens position coordinates
var lensX = e.pageX - (200 / 2);
var lensY = e.pageY - (200 / 2);
var width = $element.width();
var height = $element.height();
// Relative coordinates of image
var relX = e.pageX - $('#target').offset().left;
var relY = e.pageY - $('#target').offset().top;
// Zoomed image coordinates
var zoomX = -Math.floor(relX / width * (NATIVE_IMG.width) - 200 / 2);
var zoomY = -Math.floor(relY / height * (NATIVE_IMG.height) - 200 / 2);
var backPos = "calc(100% - " + zoomX + "px) calc(100% - " + zoomY + "px)";
var backgroundSize = NATIVE_IMG.width + "px " + NATIVE_IMG.height + "px";
// Apply styles to lens
$blowupLens.css({
left: lensX,
top: lensY,
"background-image": "url(" + encodeURI($IMAGE_URL) + ")",
"background-size": backgroundSize,
"background-position": backPos,
"transform": "rotate(-180deg)" //rotate the image original
});
})
// Hide magnification lens
$element.mouseleave(function() {
$blowupLens.css("display", "none");
});
#target {
margin-left: 160px;
width: 400;
height: 250px;
}
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<img id="target" src="https://iili.io/0hL7ou.png">
</body>
Update:
For more general case of image rotation, I'd use an additional absolutely positioned image within the lens instead of background-image. It's way easier to control:
var $pic = $('#target');
// Constants
const lensD = 70, // lens diameter
src = $pic.attr("src"),
tоp = $pic.offset().top,
lеft = $pic.offset().left;
let angle, scaleX, scaleY;
const $lens = $('<div id="lens"/>')
.css({
width: lensD,
height: lensD
})
.appendTo('body');
const $lensImage = $(`<img src="${src}">`)
.on('load', function() {
scaleX = this.width / ($pic.width() || 1);
scaleY = this.height / ($pic.height() || 1);
})
.appendTo($lens);
// Mouse motion on image
$pic.mousemove(function(e) {
// Lens position
$lens.css({
transform: (`
translateX(${e.pageX - lensD/2}px)
translateY(${e.pageY - lensD/2}px)
`)
});
// Zoomed image position
$lensImage.css({
transform: (`
translateX(${(lеft - e.pageX) * scaleX + lensD/2}px)
translateY(${(tоp - e.pageY) * scaleY + lensD/2}px)
rotateZ(${angle}deg)
`)
});
});
// Show magnification lens
$pic.mouseenter(function() {
$lens.css("display", "block");
});
// Hide magnification lens
$pic.mouseleave(function() {
$lens.css("display", "none");
});
// Rotation (aux)
$('#angle')
.on('input', function() {
$('#a').val((angle = $(this).val()) + 'deg');
$pic.css({
transform: `rotateZ(${angle}deg)`
});
$lensImage.css({
transform: `rotateZ(${angle}deg)`
});
})
.trigger('input')
.val();
#a {
border: 0
}
#target,
#lens img {
width: 200px;
height: 100px;
margin: 40px;
}
#lens {
position: absolute;
top: 0;
left: 0;
z-index: 1;
display: none;
margin: 0;
padding: 0;
border: solid 3px #0003;
border-radius: 50%;
overflow: hidden;
pointer-events: none;
}
#lens img {
position: absolute;
width: auto;
height: auto;
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<fieldset>
Rotate: <input id="a" readonly><br>
-180 <input type="range" min="-180" max="180" step="1" value="-9" id="angle"> 180
</fieldset>
<img id="target" src="https://picsum.photos/id/111/400/200">

Related

How to recalculate position of marker inside div with vh html,css,js

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?!

Horizontal scrolling menu with Javascript

I have created a menu that it is bigger than the width of the page.
And I want when it goes to it's last item, the first will appear again like a circle with no end.
here is the css code of the menu
`.slider
width: 200%
height: 65vh
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
display: flex
align-items: center
user-select: none
transition: all 0s
&:hover
cursor: grab`
and this is the js
var isDown = false;
var startX;
var mousePosition;
var offset = [0,0];
$('.slider').mousedown(function(e) {
$(this).css('cursor', 'grabbing');
$('.pointer').css({'width': '55px', 'height': '55px'});
isDown = true;
startX = e.clientX;
offset = [
this.offsetLeft - e.clientX,
this.offsetTop - e.clientY
];
// var startX = e.pageX;
// var math = Math.round(Math.sqrt(Math.pow(startX - event.clientX, 2))) + 'px';
// $(this).css('transform', 'translate(' + math + 'px, -50%)');
// console.log(math);
});
$('.slider').mousemove(function(e) {
// e.preventDefault();
if (isDown){
// var tap = $('.slider').offset().left;
// console.log(e.pageX - tap);
mousePosition = e.clientX ;
console.log(mousePosition);
// $(this).css('transform', 'translate(' + mousePosition + ', -50%)');
// console.log(e);
this.style.left = (mousePosition + offset[0]) + 'px';
startX = mousePosition;
// this.style.transform = "translate3d(" + 0 + "1110px, " + 0 + "0px, 0)";
// div.style.left = (mousePosition.x + offset[0]) + 'px';
}
});
$('.slider').mouseup(function() {
$(this).css('cursor', 'grab');
$('.pointer').css({'width': '30px', 'height': '30px'});
isDown = false;
});
When the slider goes to it's last item it ends, but I want the first one to appear again.
May I suggest using an already existing library?
There is a library called Endless.js, and this does exactly what you asked for. The demo can be found here.

Background position animation on hover

I have a div1 which animates background position on hover direction of mouse by jquery.
But it's working properly. it's going not right direction and I want it to work on every single mouse hover on the div.
Find jsfiddle
code:
$(function() {
$(".mainCont").hover(function(e) {
// $(this).addClass("hoverOnce");
var edge = closestEdge(e.pageX, e.pageY, $(this).width(), $(this).height());
}, function(){
$(this).removeClass('top right bottom left');
// $(this).removeClass("hoverOnce");
});
});
function closestEdge(x,y,w,h) {
var topEdgeDist = distMetric(x,y,w/2,0);
var bottomEdgeDist = distMetric(x,y,w/2,h);
var leftEdgeDist = distMetric(x,y,0,h/2);
var rightEdgeDist = distMetric(x,y,w,h/2);
var min = Math.min(topEdgeDist,bottomEdgeDist,leftEdgeDist,rightEdgeDist);
switch (min) {
case leftEdgeDist:
$(".hoverOnce").addClass("left");
case rightEdgeDist:
$(".hoverOnce").addClass("right");
case topEdgeDist:
$(".hoverOnce").addClass("top");
case bottomEdgeDist:
$(".hoverOnce").addClass("bottom");
}
}
function distMetric(x,y,x2,y2) {
var xDiff = x - x2;
var yDiff = y - y2;
return (xDiff * xDiff) + (yDiff * yDiff);
}
The size of this image that you use in the background is 700x500:
http://thesis2010.micadesign.org/kropp/images/research/bird_icon.png
I think that if you add these settings to .mainCont that this will get you the desired result:
width: 700px;
height: 500px;
position: absolute;
For example:
.mainCont {
width: 700px;
height: 500px;
background: url(http://thesis2010.micadesign.org/kropp/images/research/bird_icon.png) no-repeat center center;
transition: all 0.5s ease-in-out;
margin: 100px auto;
position: absolute;
}
Fiddle
Finally, It got solved.
find fiddle demo
$('.mainCont').hover(function(e){
var dir = determineDirection($(this), {x: e.pageX, y: e.pageY});
$(this).addClass('direction_'+dir);
}, function() {
$(this).removeClass('direction_3 direction_1 direction_2 direction_0');
});
function determineDirection($el, pos){
var w = $el.width(),
h = $el.height(),
x = (pos.x - $el.offset().left - (w/2)) * (w > h ? (h/w) : 1),
y = (pos.y - $el.offset().top - (h/2)) * (h > w ? (w/h) : 1);
return Math.round((((Math.atan2(y,x) * (180/Math.PI)) + 180)) / 90 + 3) % 4;
}

Auto Scroll Image vertically using JQuery

I have been trying to modify a code which scrolls the images horizontally. I want to scroll it vertically. I don't know JQuery at all. After trying for hours I couldn't find any way to sort this thing out. Can anyone help me out in this regard.
Heres the whole code.
$(function() {
$(window).load(function() {
var $gal = $("#propertyThumbnails"),
galW = $gal.outerWidth(true),
galSW = $gal[0].scrollWidth,
wDiff = (galSW / galW) - 1, // widths difference ratio
mPadd = 60, // Mousemove Padding
damp = 20, // Mousemove response softness
mX = 0, // Real mouse position
mX2 = 0, // Modified mouse position
posX = 0,
mmAA = galW - (mPadd * 2), // The mousemove available area
mmAAr = (galW / mmAA); // get available mousemove fidderence ratio
$gal.mousemove(function(e) {
mX = e.pageX - $(this).parent().offset().left - this.offsetLeft;
mX2 = Math.min(Math.max(0, mX - mPadd), mmAA) * mmAAr;
});
setInterval(function() {
posX += (mX2 - posX) / damp; // zeno's paradox equation "catching delay"
$gal.scrollLeft(posX * wDiff);
}, 10);
});
});
#parent {
position: relative;
margin: 0 auto;
width: 100%;
background: #ddd;
}
#propertyThumbnails {
position: relative;
overflow: hidden;
background: #444;
width: 100%;
white-space: nowrap;
}
#propertyThumbnails img {
vertical-align: middle;
display: inline;
margin-left: -4px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="parent">
<div id="propertyThumbnails">
<img src="http://placehold.it/1000x100" />
</div>
</div>
Heres the demo:
http://jsbin.com/alokat/1/edit?html,css,js,output
I changed the script as
$(function(){
$(window).load(function(){
var $gal = $("#propertyThumbnails"),
galW = $gal.outerHeight(true),
galSW = $gal[0].scrollHeight,
wDiff = (galSW/galW)-1, // widths difference ratio
mPadd = 60, // Mousemove Padding
damp = 20, // Mousemove response softness
mX = 0, // Real mouse position
mX2 = 0, // Modified mouse position
posX = 0,
mmAA = galW-(mPadd*2), // The mousemove available area
mmAAr = (galW/mmAA); // get available mousemove fidderence ratio
$gal.mousemove(function(e) {
mX = e.pageY - $(this).parent().offset().top - this.offsetTop;
mX2 = Math.min( Math.max(0, mX-mPadd), mmAA ) * mmAAr;
});
setInterval(function(){
posX += (mX2 - posX) / damp; // zeno's paradox equation "catching delay"
$gal.scrollTop(posX*wDiff);
}, 10);
});
});

How to draw a line beet wen two points in loop?

I have an animations with jQuery which looks like that:
$(function() {
var elems = $('div.icon').not('#icon-0');
var increase = Math.PI * 2 / elems.length,
x = 0,
y = 0,
angle = 0,
radius = 200;
var center_top = ($("#slider-1").outerHeight() - $("#icon-0").outerHeight())/2,
center_left = ($("#slider-1").outerWidth() - $("#icon-0").outerWidth())/2;
$('.icon').css({
'top': center_top + 'px',
'left': center_left + 'px'
});
$(elems).css('opacity', '0').each(function(i) {
elem = elems[i];
x = radius * Math.cos(angle) + center_left;
y = radius * Math.sin(angle) + center_top;
$(elem).delay(400*i).animate({
'position': 'absolute',
'left': x + 'px',
'top': y + 'px',
'opacity': '1'
}, 1000);
angle += increase;
});
});
http://jsfiddle.net/d6pYR/
How do I write the line between the circle in the center and each of the outer circles?
I tried with the canvas and getting center coordinates via offset and some easy math, but canvas wouldn't do it properly or I just can't do that.
I'd appreciate any help from you guys.
Cheers!
taking into mind that you do not want to use canvas (or is not feasible) made ​​a solution using css3 transform ...
follows the solution
in this JSFiddle -> http://jsfiddle.net/d6pYR/2/
you need to create more one css class to make a line
.line {
border-top: 1px solid black;
position: absolute;
height: 1px;
opacity: 0;
-webkit-transform-origin: left;
transform-origin: left;
}
to create a element you can create in loop
var line = $("<div class='line'></div>");
slider.append(line);
line.css("width", 0);
line.css("top", center_top + ( $(this).height() / 2 ) );
line.css("left", center_left + ( $(this).width() / 2 ) );
line.css("transform", "rotateZ(" + angle + "rad)");

Categories

Resources