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)");
Related
Let's say I have svg, drawn like this:
var myArc = d3.svg.arc()
.innerRadius(width / 5)
.outerRadius(width / 2);
myArc.startAngle(function(d, i) {
return radians * i
});
myArc.endAngle(function(d, i) {
return radians * (i + 1)
...and is later filled with some color, etc. It looks like this:
Now, I want on svg click to get angle degree. Example: I want to get between ~ 310° and 50° when I click on red, 70° or so when I click on yellow etc.
How would I do that? Thanks in advance.
I do some research, didn't find any simpler solution.
I am using the way you mentioned: get center of circle and clicked position, then calculate angle based on those two. I don't think this is too complex to use.
Note: because the circle is not really circle, so there are some numerical errors.
Hope this is useful.
(function($){
var center = {};
var calculateAngle = function(x, y){
var k = Math.abs(y) / Math.abs(x);
var angle = Math.atan(k) * 180 / Math.PI;
if(y * x > 0){
angle = 90 - angle + (y < 0 ? 180 : 0);
} else {
angle = angle + (y < 0 ? 90 : 270);
}
return angle;
}
$(document).ready(function(){
var $container = $('#container');
var $selector = $('#selector');
var $result = $('#result');
center = {
x: $container.width() / 2,
y: $container.height() / 2
}
$selector.css({left:center.x, top:center.y});
$container.on('click', function(e){
var x = e.offsetX;
var y = e.offsetY;
$selector.css({left:x, top:y});
var angle = calculateAngle(x - center.x, center.y - y);
$result.text(angle);
});
});
})(jQuery)
#container{
display: inline-block;
border: 1px solid red;
width: auto;
position: relative;
}
#selector{
position: absolute;
border:1px solid black;
width: 5px;
height: 5px;
border-radius: 50%;
transform: translate(-50%, -50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
<span id="selector"></span>
<img src="http://i.stack.imgur.com/4X8A7.png">
</div>
<div>
<span>Result: </span>
<span id="result"></span>
</div>
I have a wrapper called #mousearea and I have a div called #mouseshift what I would like to do is when I hover over #mousearea I would like to shift the translate3d(0,230%,0) value between a particular range.
I have got the mousemove working but I currently end up with something like translate3d(7881%,230%,0) it's just too sensetive I would like it to translate the X co-ordinate between something like 0-60% so it's far more subtle.
Here is what I have so far:
jQuery(document).ready(function($){
$('#mousearea').mousemove(function (e) {
var shiftAmount = 1;
$('#mouseshift').css(
'transform', 'rotate(90deg) translate3d(' + -e.pageY + shiftAmount + '%,230%,0)'
);
});
});
Update:
This is a little closer, except it logs the correct translate3d but doesn't apply it to #mouseshift.
$('#mousearea').mousemove(function(e){
var x = e.pageY - this.offsetTop;
var transfromPosition = 'translate3d(' + x + ', 230%, 0)';
console.log(transfromPosition);
if ((x <= 800)) {
//$('#mouseshift').css({'top': x});
$('#mouseshift').css('transform', transfromPosition);
}
});
Final Solution:
jQuery(document).ready(function($){
$('#mousearea').mousemove(function(e){
var min = 50;
var max = 70;
var x = e.pageY;
var windowHeight = window.innerHeight;
scrolled = (x / windowHeight);
percentageScrolled = scrolled * 100;
offsetScroll = max - min;
offsetPercentage = scrolled * 20;
translateX = min + offsetPercentage;
console.log(x + 'px');
console.log(windowHeight + 'px window height');
console.log(percentageScrolled + '% scrolled');
console.log(offsetScroll + 'offset scroll');
console.log(offsetPercentage + '% offset percentage');
var transfromPosition = 'rotate(90deg) translate3d(' + translateX + '%, 230%, 0)';
$('#mouseshift h1').css('transform', transfromPosition);
});
});
Convert to a reusable plugin I would like to extend this to work with more than one object now and each object would have a different max and min value:
This is what I have but it seems to effect all the items on only use on elements max and min.
$(function () {
$('#mouseshift-1, #mouseshift-2').mouseShift();
});
(function ($) {
$.fn.mouseShift = function () {
return this.each(function () {
var myEl = $(this);
var min = $(this).data('min');
var max = $(this).data('max');
$('#mousearea').mousemove(function (e) {
var yPosition = e.pageY;
var windowHeight = window.innerHeight;
scrolled = (yPosition / windowHeight);
//percentageScrolled = scrolled * 100;
offsetRange = max - min;
offsetRangePercentage = scrolled * 20;
offset = min + offsetRangePercentage;
//// Debug
console.log('max: ' + max + ', Min:' + min);
console.log(yPosition + 'px');
console.log(windowHeight + 'px window height');
//console.log(percentageScrolled + '% scrolled');
console.log(offsetRange + 'px offset scroll');
console.log(offsetRangePercentage + '% offset percentage');
var transfromPosition = 'rotate(90deg) translate3d(' + offset + '%, 230%, 0)';
myEl.css('transform', transfromPosition);
});
});
};
})(jQuery);
And some HTML for clarity:
<div class="column"><h1 id="mouseshift-1" data-min="50" data-max="70">boo</h1></div>
<div class="column"><h1 id="mouseshift-2" data-min="20" data-max="90">bah</h1></div>
<div class="column"><h1 id="mouseshift-3" data-min="80" data-max="100">bing</h1></div>
I think what you are looking for is finding an average that your can distribute. The best way to do this is to divide by the maximum amount it can move, and multiply it by the maximum value it can have, so basically:
position / maxposition * maxvalue
The first bit will return a number between 0 and 1, while the last bit will make it the value between 0 and 60. Below I have built a simply (jquery-less) version of it to show how this would work:
var mousePointer = document.getElementById('test')
document.addEventListener('mousemove', function(e){
var x = e.pageX / window.innerHeight;
x = x * -60;
mousePointer.style.webkitTransform = 'translateX(' + x + '%)';
mousePointer.style.transform = 'translateX(' + x + '%)';
})
#test {
position: absolute;
left: 50%;
top: 50%;
width: 20px;
height: 20px;
background: red;
}
<div id="test"></div>
Update: Reusable Snippet
I don't really like using jQuery, so once again it will be vanilla javascript (but it's pretty simple). Is that what you were - sort of - trying to do with the reusable plugin?
var divs = Array.prototype.slice.call(document.querySelectorAll('[data-range]'));
document.addEventListener('mousemove', function(e){
var eased = e.pageX / window.innerWidth;
divs.forEach(function(div){
var range = div.getAttribute('data-range').split(',');
var min = parseFloat(range[0]);
var max = parseFloat(range[1]);
var ease = min + (eased * (max - min));
div.style.webkitTransform = 'translateX(' + ease + '%)';
div.style.transform = 'translateX(' + ease + '%)';
});
});
div {
position: absolute;
left: 50%;
top: 50%;
width: 200px;
height: 200px;
background: gray;
}
#d2 { background: yellow; }
#d3 { background: #666; }
<div data-range="60,70" id="d1"></div>
<div data-range="-70,70" id="d2"></div>
<div data-range="-60,-70" id="d3"></div>
From simple reading, I see that you're missing a % sign. Should be like this:
$('#mousearea').mousemove(function(e){
var x = e.pageY - this.offsetTop;
var transfromPosition = 'translate3d(' + x + '%, 230%, 0)';
console.log(transfromPosition);
if ((x <= 800)) {
//$('#mouseshift').css({'top': x});
$('#mouseshift').css('transform', transfromPosition);
}
});
This should be working like your first example, where you do use % for both values inside the translate3d string.
Update:
To coerce your x Value to something between 0 and 60, you need to find a pair of possible min and max values for x. Then you can do something like what's shown in this answer:
Convert a number range to another range, maintaining ratio
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;
}
I'm trying to scale some divs inside a 'workspace' div. The problem I have are with the distance between them (I lose it).
I have read a lot of post about CSS3 transform, in special about scale and translate and origin, but I can't solve the problem...
Can someone explain me how can I keep them? I show one code using a mousewheel plugin, regards.
HTML
<body>
<div id="workspace">
<div style="z-index: 101;"><img src="image1-300x300.jpg" /></div>
<div style="z-index: 102; left: 300px; top: 400px;"><img src="image2-400x400.jpg" /></div>
</div>
</body>
CSS
#workspace {
width: 1600px;
height: 900px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: inline;
}
#workspace > div {
display: inline;
position: absolute;
}
JAVASCRIPT
$(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
// if mousewheel is moved
$("#workspace").mousewheel(function (e, delta) {
// find current location on screen
var xScreen = e.pageX - $(this).offset().left;
var yScreen = e.pageY - $(this).offset().top;
// find current location on the image at the current scale
xImage = xImage + ((xScreen - xLast) / scale);
yImage = yImage + ((yScreen - yLast) / scale);
// determine the new scale
if (delta > 0) {
scale *= 2;
}
else {
scale /= 2;
}
scale = scale < 1 ? 1 : (scale > 64 ? 64 : 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
$('#mosaicContainer > div').each(function() {
$(this).css('-webkit-transform', 'scale(' + scale + ')' + 'translate(' + xNew + 'px, ' + yNew + 'px' + ')')
.css('-webkit-transform-origin', (xImage) + 'px ' + (yImage) + 'px');
});
return false;
});
});
I'm getting absolutely positioned rotated elements position with jQuery .position() method, then setting position-related attributes (top, left) with jQuery .css(pos), where pos is the data returned by .position(). I think it'll leave the element in it's place, but elements position is changing.
How can I use set rotated elements position, so that it'll be placed as expected? Maybe there is a coefficient depended on angle that changes position?
I'm testing in Google Chrome v.9, Windows XP.
HTML
<div id="container">
<div id="element">
<img src="http://t0.gstatic.com/images?q=tbn:ANd9GcS0Fawya9MVMez80ZusMVtk_4-ScKCIy6J_fg84oZ37GzKaJXU74Ma0vENc"/>
</div>
</div>
CSS
#container {
position: relative;
border: 1px solid #999;
padding: 5px;
height: 300px;
width:300px;
}
#element {
position: absolute;
top:50px;
left: 60px;
width: auto;
border: 1px solid #999;
padding: 5px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
}
JS
$(document).ready(function(){
var $el = $('#element'),
// getting position
pos = $el.position();
alert(pos.left + '/' + pos.top);
// alerts 37/11
// setting css position attributes equal to pos
$el.css(pos);
// re-getting position
pos = $el.position();
alert(pos.left + '/' + pos.top);
// alerts 14/-28
});
View it http://jsfiddle.net/Antaranian/2gVL4/
// Needed to read the "real" position
$.fn.adjustedPosition = function() {
var p = $(this).position();
return {
left: p.left - this.data('dx'),
top: p.top - this.data('dy')
}
};
$(function() {
var img = $('img'),
pos;
// Calculate the delta
img.each(function() {
var po = $(this).position(), // original position
pr = $(this).addClass('rot').position(); // rotated position
$(this).data({
dx: pr.left - po.left, // delta X
dy: pr.top - po.top // delta Y
});
});
// Read the position
pos = img.adjustedPosition();
alert(pos.left + '/' + pos.top);
// Write the position
img.css(pos);
// Read the position again
pos = img.adjustedPosition();
alert(pos.left + '/' + pos.top);
});
Live demo: http://jsfiddle.net/2gVL4/4/
So what is going on here:
The CSS code that rotates the image is stored inside a special CSS class. I do this because I want to read the original position of the image (before rotating). Once I read that original position, I apply the .rot class, and then read the position again to calculate the difference (delta), which is stored inside the element's data().
Now, I can read the position via the custom method adjustedPosition (which is defined above). This method will read the position of the element and then subtract the delta values stored inside the data() of the element.
To write the position, just use the css(pos) method like normally.
Had similar problem. There is simple solution (not elegant, but working):
set current angle to 0
read X/Y position
revert angle back to its value
var temp = $(this).position();
temp.angle = getRotationDegrees( $(this) ); // remember current angle
rotateObject($(this), 0); // set angle to 0
temp.left = Math.round($(this).position().left); // proper value
temp.top = Math.round($(this).position().top); // proper value
// revert back the angle
rotateObject($(this), temp.angle);
Used functions:
function rotateObject(obj, angle) {
obj.css({ '-webkit-transform': 'rotate(' + angle + 'deg)'});
obj.css({ '-moz-transform': 'rotate(' + angle + 'deg)'});
obj.css({ '-ms-transform': 'rotate(' + angle + 'deg)'});
obj.css({ 'msTransform': 'rotate(' + angle + 'deg)'});
obj.css({ '-o-transform': 'rotate(' + angle + 'deg)'});
obj.css({ '-sand-transform': 'rotate(' + angle + 'deg)'});
obj.css({ 'transform': 'rotate(' + angle + 'deg)'});
}
function getRotationDegrees(obj) {
var matrix = obj.css("-webkit-transform") ||
obj.css("-moz-transform") ||
obj.css("-ms-transform") ||
obj.css("-o-transform") ||
obj.css("transform");
if(matrix !== 'none') {
var tr;
if (tr = matrix.match('matrix\\((.*)\\)')) {
tr = tr[1].split(',');
if(typeof tr[0] != 'undefined' && typeof tr[1] != 'undefined') {
var angle = Math.round(Math.atan2(tr[1], tr[0]) * (180/Math.PI));
}else{
var angle = 0;
}
}else if(tr = matrix.match('rotate\\((.*)deg\\)')){
var angle = parseInt(tr[1]);
}
} else { var angle = 0; }
return (angle < 0) ? angle + 360 : angle;
}