I would like to monitor visually the zooming focal point in the panzooom jquery plugin. in order to do so, I would like to position a little 10x10 div on the same coordinates as the focal point, but somehow it is placing it in a totally different location. Here is my code:
(only posting relevant parts)
$panzoom.panzoom("option", {
contain: false,
increment: 10,
duration: 2000,
animate: true,
exponential: false,
minScale: minScale,
maxScale: maxScale,
panOnlyWhenZoomed : false,
focal: {
clientX: position.left, //coordinates of an existing div.
clientY: position.top
}
});
$panzoom.panzoom('zoom');
var d = document.getElementById('zoomcenter');
d.style.left = position.left+'px';
d.style.top = position.top+'px'; // I expect this div to be
// placed in the same position as the above,
// where I am zooming to. Instead it is placed
// somewhere totally different.
// probably affected by the transform Matrix.
// but not able to figure out why.
var matrix = $panzoom.panzoom("getMatrix");
console.debug("boxl:" + position.left + " boxt:" + position.top + " zcl:" + $('#zoomcenter').offset().left + " zct:" + $('#zoomcenter').offset().top + " Matrix:" + matrix.toString())
//returns this:
// boxl:986.6997680664062 boxt:343.0241394042969 zcl:692.1810302734375 zct:285.1896057128906 Matrix:1.6775,0,0,1.6775,-1133.01,-244.451
EDIT: Additional info:
- the div zoomcenter has absolute positioning.
- the position of $panzoom.panzoom('zoom') does not affect the result.
Related
Is it possible the "Swap out" draggable items using InteractJS, when dragging a draggable item from a "origin" to a "target" zone?
I cannot find any reference in their Documentation https://interactjs.io/docs about this specific use case
To explain better the situation and goal I made this rough fiddle:
https://jsfiddle.net/09afor6w/
It has 2 draggable "boxes" each in a "parent box". When dragging the first box to the second, the second should automatically swap locations with the first, instead of staying put, or at least not allow the dragged element to be superposed to the element already there.
I assumed they would have a specific "swap" feature but it does not seem so.
With the "restrict" method, I can only restrict size and area of (size and drag), but not control that no items should overlap and thus maybe use this as a workaround to create a "swap" experience.
The goal behind this is creating a UI where the user can drag and drop single form elements into different places in a restricted, "gridded" area and resize the form elements.
When dragging elements from A to B, the element from the target area should change location to the "origin" area of the dragged item, that's all.
So if there is an easier, lighter way to do this, I am also happy to hear about.
This is the code I use.
HTML:
<div class="contain-all">
<div class="contain-some">
<div class="grid-snap">
Move this box to the white target area below
</div>
</div>
<div class="contain-some">
<div class="grid-snap">
This box should automatically swap place with the moved box
</div>
</div>
</div>
JS:
var elements = document.getElementsByClassName('grid-snap');
$(elements).each(function(){
var x = 0; var y = 0
interact(this)
.resizable({
// resize from all edges and corners
edges: { left: true, right: true, bottom: true, top: true },
listeners: {
move (event) {
var target = event.target
var x = (parseFloat(target.getAttribute('data-x')) || 0)
var y = (parseFloat(target.getAttribute('data-y')) || 0)
// update the element's style
target.style.width = event.rect.width + 'px'
target.style.height = event.rect.height + 'px'
// translate when resizing from top or left edges
x += event.deltaRect.left
y += event.deltaRect.top
target.style.transform = 'translate(' + x + 'px,' + y + 'px)'
target.setAttribute('data-x', x)
target.setAttribute('data-y', y)
}
},
modifiers: [
// keep the edges inside the parent
interact.modifiers.restrictEdges({
outer: 'parent'
}),
// minimum size
interact.modifiers.restrictSize({
min: { width: 100, height: 50 }
})
],
inertia: true
})
.draggable({
listeners: { move: window.dragMoveListener },
inertia: true,
modifiers: [
interact.modifiers.restrictRect({
restriction: '#formthing',
}),
interact.modifiers.snap({
targets: [
interact.snappers.grid({ x: 30, y: 30 })
],
range: Infinity,
relativePoints: [ { x: 0, y: 0 } ]
}),
]
})
.on('dragmove', function (event) {
x += event.dx
y += event.dy
event.target.style.transform = 'translate(' + x + 'px, ' + y + 'px)'
})
});
What I'm looking to accomplish is to get the position of the mouse in relation to a zoomed out div with matrix transform. As you will see in the fiddle below I have a red div with a width of 4000px, but since it's zoomed out it appears smaller then said 4000px. What should happen is if you click on the intersecting lines in the red div, relX should read (around) 2000 and relY should read around 325.
$(".crazyWide").click(function(e){
var clickPos = $(this).offset();
var relX = e.pageX - clickPos.left;
var relY = e.pageY - clickPos.top;
//Used to display current click coords
$(".debug").empty();
$(".debug").prepend("relX: " + relX + " relY: " + relY);
});
Fiddle
The element is shrunk to a factor of 0.12 in both directions. As such, you can calculate the relative mouse click position by dividing the relX and relY by 0.12:
$(".debug").prepend("relX: " + (relX / 0.12) + " relY: " + (relY / 0.12));
Updated fiddle
Full code can be viewed on JSBin - http://jsbin.com/inibAya/1/edit
So I'm working on a wysiwyg website designer and I added a crosshair to show the corrinates the mouse position is within the canvas. (NOTE: a div acts as the canvas not a html5 canvas element)
The div#canvas is positioned at...
#canvas {
position: absolute;
top:0; left:44px; right:291px; bottom:16px;
overflow: auto;
}
Whatever calculation I tried to remove the 44px from the canvas's display I got NaN or undefined. When the user moves their mouse I want it to start at 0 from the top left and move onwards. Does anyone know of anyway to get this to work?
Here's my JQuery/JavaScript:
// Crosshair
var cH = $('#crosshair-h'), cV = $('#crosshair-v');
$('#canvas').mousemove(function(e) {
cH.css('top', e.pageY);
cV.css('left', e.pageX);
$('#mousepos').text( "X: " + e.pageX + "px, Y: " + e.pageY + "px");
});
From e.pageX's documentation:
Description: The mouse position relative to the left edge of the document.
You will need to account for your canvas's offset (of 44px) to solve your problem.
var canvasPosition = $(canvas).position();
$(canvas).on('mousemove', function(e) {
var x = e.pageX - canvasPosition.left;
var y = e.pageY - canvasPosition.top;
cH.css('top', e.pageY);
cV.css('left', e.pageX);
$('#mousepos').text( "X: " + x + "px, Y: " + y + "px");
});
JSBin.
This seems like it should be quite simple, but for some reason I can't quite wrap my brain around it. I have an image inside a "viewport" div, of which the overflow property is set to hidden.
I've implemented a simple zooming and panning with jQuery UI, however I am having trouble getting the zoom to appear to originate from the center of the viewport. I did a little screencast from Photoshop the effect I'm trying to reproduce: http://dl.dropbox.com/u/107346/share/reference-point-zoom.mov
In PS you can adjust the scaling reference point an the object will scale from that point. Obviously this is not possible with HTML/CSS/JS, so I'm trying to find the appropriate left and top CSS values to mimic the effect.
Here is the code in question, with a few unnecessary bits removed:
html
<div id="viewport">
<img id="map" src="http://dl.dropbox.com/u/107346/share/fake-map.png" alt="" />
</div>
<div id="zoom-control"></div>
javascript
$('#zoom-control').slider({
min: 300,
max: 1020,
value: 300,
step: 24,
slide: function(event, ui) {
var old_width = $('#map').width();
var new_width = ui.value;
var width_change = new_width - old_width;
$('#map').css({
width: new_width,
// this is where I'm stuck...
// dividing by 2 makes the map zoom
// from the center, but if I've panned
// the map to a different location I'd
// like that reference point to change.
// So instead of zooming relative to
// the map image center point, it would
// appear to zoom relative to the center
// of the viewport.
left: "-=" + (width_change / 2),
top: "-=" + (width_change / 2)
});
}
});
Here is the project on JSFiddle: http://jsfiddle.net/christiannaths/W4seR/
Here's the working solution. I will explain the logic at the next edit.
Function Logic:
Summary: Remember the center position of the image, relatively.
The calculations for width and height are similar, I will only explain the height calculationThe detailled explanation is just an example of function logic. The real code, with different variable names can be found at the bottom of the answer.
Calculate the center (x,y) of the #map, relative to #viewport. This can be done by using the offset(), height() and width() methods.
// Absolute difference between the top border of #map and #viewport
var differenceY = viewport.offset().top - map.offset().top;
// We want to get the center position, so add it.
var centerPosition = differenceY + viewport.height() * 0.5;
// Don't forget about the border (3px per CSS)
centerPosition += 3;
// Calculate the relative center position of #map
var relativeCenterY = centerPosition / map.height();
// RESULT: A relative offset. When initialized, the center of #map is at
// the center of #viewport, so 50% (= 0.5)
// Same method for relativeCenterX
Calculate the new top and left offsets:
// Calculate the effect of zooming (example: zoom 1->2 = 2)
var relativeChange = new_width / old_width;
// Calculate the new height
var new_height = relativeChange * old_height;
// Calculate the `top` and `left` CSS properties.
// These must be negative if the upperleft corner is outside he viewport
// Add 50% of the #viewport's height to correctly position #map
// (otherwise, the center will be at the upperleft corner)
var newTopCss = -relativeCenterY * new_height + 0.5 * viewport.height();
Change the CSS property
map.css("top", newTopCss);
Demo: http://jsfiddle.net/W4seR/12/
var map = $('#map');
var viewport = $('#viewport');
// Cache the size of the viewport (300x300)
var viewport_size = {
x: viewport.width(),
y: viewport.height()
};
map.draggable();
$('#zoom-control').slider({
min: 300,
max: 1020,
value: 300,
step: 24,
create: function() {
map.css({
'width': 300,
'left': 0,
'top': 0
});
},
slide: function(event, ui) {
var old_width = map.width();
var old_height = map.height();
var viewport_offset = viewport.offset();
var offset = map.offset();
offset = {
top: viewport_offset.top - offset.top + .5*viewport_size.y +3,
left: viewport_offset.left - offset.left + .5*viewport_size.x +3
};
// Relative offsets, relative to the center!
offset.top = offset.top / old_height;
offset.left = offset.left / old_width;
var new_width = ui.value;
var relative = new_width / old_width;
var new_height = relative * old_height;
offset = {
top: -offset.top * new_height + .5*viewport_size.y,
left: -offset.left * new_width + .5*viewport_size.x
};
var css_properties = {
width: new_width,
left: offset.left,
top: offset.top
};
map.css(css_properties);
trace((map.position().left));
}
});
I have always relied on the kindness of strangers. Pertinent changes:
// Calculate the offset as a percentage, accounting for the height of the window
var x_offset = ((map.position().left-150))/(old_width/2);
var y_offset = ((map.position().top-150))/(old_width/2);
var css_properties = {
width: new_width,
// Set the offset based on the existing percentage rather than 1/2
// then readjust for the height of the window
left: (new_width * x_offset /2 ) + 150 + "px",
top: (new_width * y_offset /2 ) + 150 + "px"
};
Replace the hardcoded 150 with a variable set on viewport instantiation if necessary.
Here is a quick working version:
http://jsfiddle.net/flabbyrabbit/chLkZ/
Probably not the neatest solution but seems to work nicely, hope it helps.
Update: sorry this only works if zoom is 0 when the map is moved.
I am creating an animation that changes the value of a background image. It is working perfectly if I hard code in the coordinates, but I am trying to modify it so that it simnply increments the position by 20px.
Here's the code I am using to retrieve the original Y position - works perfectly:
$('.rss,.twitter,.jquery').each(function(){
// Returns "##px" and "##px"
var backgroundPositions = $(this).css('background-position').split(" ");
// Retrieve the original Y position
$(this).data("originalYpos", backgroundPositions[1].slice(0, -2));
});
Now I am trying to increment the value of originalYpos by 20px but this isn't working:
var animateNum = function() {
$('.rss,.twitter,.jquery').animate({
var YPos = $(this).data('originalYpos')+20;
backgroundPosition: 0 + "px " + YPos + "px"}, 400, "easeOutCirc");
};
I do believe it is because the declaration of var Ypos isn't allowed inside the .animate(), but I need to refer to $(this), meaning the value of each of the 3 individual selectors as they are being animated.
Any suggestions are greatly appreciated!
Try:
var animateNum = function() {
$('.rss,.twitter,.jquery').animate({
backgroundPosition: "0 " + ($(this).data('originalYpos')+20) + "px"
}, 400, "easeOutCirc");
};
Why store the old value at all:
From http://api.jquery.com/animate/
Animated properties can also be relative. If a value is supplied with a leading += or -= sequence of characters, then the target value is computed by adding or subtracting the given number from the current value of the property.
So, the code below should work (although I haven't tried it myself)
var animateNum = function() {
$('.rss,.twitter,.jquery').animate({
backgroundPosition: "+=20px"
}, 400, "easeOutCirc");
};
Should be like this:
var animateNum = function() {
$('.rss,.twitter,.jquery').animate({
backgroundPosition: $(this).data('originalYpos')+20 + "px"}, 400, "easeOutCirc");
};