Restrict jQuery/CSS3 rotate logic to always rotate clockwise - javascript

I'm using the jQuery transit plugin to rotate a block element with 4 navigation controls; each time a nav item is clicked, the rotated block should rotate to the custom data attribute of that nav item (either 0, 90, 180 or 270 degrees).
I can successfully do this (see my jsfiddle: http://jsfiddle.net/xkdgdhbk/, only tested in chrome), but I would like to restrict the rotation to ALWAYS go clockwise. As you can see, if you click 180deg it will go clockwise, but then if you click 90deg, it will go anti-clockwise. I would like the element to rotate clockwise at all times, if possible.
Is there a way to achieve this?
Here's my script from the jsfiddle:
$("span").click(function(){
$(".rotate").transition({ rotate: $(this).attr("data-rotate") + "deg"});
});

You can store the previous rotate value in the $(.rotate) element and use it for each rotation something like this
$().ready(function()
{
$("span").click(function()
{
var lastRotate = $(".rotate").attr("data-rotate");
if(lastRotate ==undefined)
{
lastRotate = 0;
}
lastRotate = parseInt(lastRotate);
var newRotate = lastRotate + parseInt($(this).attr("data-rotate"));
$(".rotate").transition({ rotate:newRotate + "deg"}).attr("data-rotate",newRotate);
});
});

Related

How to change the cursor on an image on mouse move

In an Angular 7 application, I'm trying to implement left and right arrows for an image slideshow. If the mouse is hovered on the left half of the image, it should show a left arrow, and a right arrow on the right half. Clicking the image then will take the user to either the next or previous image in the array of images. Something like this: https://wells-demo.squarespace.com/human-nature-wells/uml9t64gkm48jijkt8y6slmtd0jush
<img src="url" (click)="navigate()">
I tried to set up something with #HostListener, but can't quite figure out how to progress.
urls = [url1, url2, url3, ....url10];
currIndex = 2;
url = urls[currIndex];
#HostListener('mousemove', ['$event'])
onMouseMove(event: MouseEvent) {
//console.log(event.pageX);
//console.log(this.el.nativeElement.offsetLeft);
//not completely sure what to do here...
}
navigate() {
if (leftHalf) { //how to figure this out?
prevImage();
} else {
nextImage();
}
nextImage() {
this.url = this.urls[this.currIndex + 1];
}
prevImage() {
this.url = this.urls[this.currIndex - 1]
}
1) How do I change the mouse cursor to a left arrow based on the position?
2) How to detect if left half or right half was clicked on?
Appreciate any help I can get on this!
Make use of offsetWidth of the element and offsetX of the mousemove event.
if(event.offsetX > element.offsetWidth / 2) {
// right half
} else {
// left half
}
To change the pointer's you have to make use of add/remove class using the cursor property. Refer this https://css-tricks.com/using-css-cursors/
check out the below code for adding arrows as per your requirement
.left_div{
cursor:w-resize;
float:left
}
.right_div{
cursor:n-resize;
float:right
}
<div class="left_div">this is left div</div>
<div class="right_div">this is right div</div>

Transform rotate in snap svg

Here is a JS FIDDLE where I am trying to rotate one of the cogwheel, but it rotates by moving to a different point. I tried different values to rotate it from the center without any luck. Any help will be very appreciated.
code
var s = Snap("#main");
var orange = s.select("#orgBearing");
rotating();
function rotating() {
orange.stop().animate({
transform: 'R360 126.7 126.7'
}, 1000);
}
Would also love to see if this animation can be made to repeat indefinitely.
You need to calculate the center of your object, so you rotate around the correct point.
var bbox = orange.getBBox(); //bounding box, get coords and centre
orange.stop().animate({ transform: "r360," + bbox.cx + ',' + bbox.cy }, 1000);
Here is a solution:
https://jsfiddle.net/cfogknc5/1/
You can just call setInterval() on your rotating function to make an infinite loop.

Loop with overlay on hovered item via css

I have to make some basic feature in one project. We have four elements, and when someone hovers on one of them, it should get yellow border (overlay). Overlay element should rotate in a circle and be always visible.
It should look like this:
I've write a script in JS that rotate overlay element via css rotate, but I dont know how to loop it.. I mean when somebody hovers elements its working correctly, but when somebody hover last element (on the left) and next hover first element (on the top), then overlay element return back (move in different direction) - I know it's correct behavior, but I dont know how to loop this move that everytime overlay element will move in this same direction.
You can see basic markup I've made in codepen. It's not styled correctly, but I think most important here is JS right now.
LINK
JS:
// HOMEPAGE CIRCLE
var circle = $('#circle'),
elems = $('.home-single-item'),
overlay = $('#home-overlay'),
arrow = $('.home-arrow'),
texts = $('.home-single-item-text');
texts.eq(0).addClass('active');
elems.on( 'mouseover', function( event ) {
var index = $(this).index();
if ( index === 2 ) {
index = 3;
} else if ( index === 3 ) {
index = 2;
}
var rotate = index * 90;
var arrowz = ( index + 2 ) * 90;
console.log( index );
console.log( rotate );
overlay.css({
'transform': 'rotate(' + rotate + 'deg)'
});
arrow.css({
'transform': 'rotate(' + arrowz + 'deg)'
});
texts.removeClass('active');
texts.eq(index).addClass('active');
});
Thanks in advance.
You essentially need to have a rotation value that is always higher than the previous one.
This is just fairly messy psuedo code, but you could try something along the lines of:
var prevRotate;
elems.on( 'mouseover', function( event ) {
// snip
var rotate = index * 90;
if(prevRotate && rotate < prevRotate){
rotate = rotate + Math.ceil(prevRotate/360) * 360;
}
prevRotate = rotate;
// snip
});
It might not work immediately, but ensuring that the new rotation is more than the previous rotation is what you want.

SVG: Scale one element of group from specified anchor point

OK, so I have a group of four elements rotating 90 degrees as I want them to, around an origin point in the middle of the four elements.
I would like to scale the top left block before and after spinning as well, outward from said origin point, but I'm having much difficulty doing so.
Here is a fiddle for my sample (read: overly simplified) progress so far:
http://jsfiddle.net/Vac2Q/2843/
The fiddle's javascript:
/* create an svg drawing */
var draw = SVG('drawing')
/* draw rectangle */
var dial = draw.circle(60)
.move(125,125)
.fill('#0099ff')
var rect_yellow = draw.rect(50,50)
.move(100,100)
.fill('gold')
var rect_blue = draw.rect(50,50)
.move(160,100)
.fill('navy')
var rect_black = draw.rect(50,50)
.move(160,160)
.fill('black')
var rect_green = draw.rect(50,50)
.move(100,160)
.fill('green')
var blades = draw.group()
.add(rect_yellow)
.add(rect_blue)
.add(rect_black)
.add(rect_green)
.back()
var angle = 0
var rotation = 90
var spin = document.getElementById('spin')
var spun = 0
/* make rectangle jump and change color on mouse over */
spin.addEventListener('click', function() {
/* calculate new ending orientation for blades */
angle += rotation
var new_rotate = angle
/* rotate the blade group */
blades.animate(1000, '>')
.rotate(new_rotate, 155, 155)
++spun
})
And here is a slightly more glamorous example of what I'm trying to do re: scaling:
The first issue is being able to determine which blade is in the top left position after a given rotation. The second issue is scaling itself; I've gotten the blade to scale, but then it goes crazy and moves off the screen at the same time. I'm not sure how to get it to scale properly from the specified origin point (the middle of the center circle).
You can use the .after() function to chain animations.
I'm not sure if I am using svg.js correctly, but here's what I did:
var rects = [rect_yellow, rect_green, rect_black, rect_blue];
// define the animations
var enlarge_blade = function() {
rects[spun % 4].animate(250, '<')
.scale(1.25, 1.25)
.translate(-38,-38);
};
function spin_anim() {
rects[spun % 4].animate(250, '>')
.scale(1, 1)
.translate(0,0)
.after(rotate_blades);
};
var rotate_blades = function() {
blades.animate(1000, '>')
.rotate(angle, 155, 155)
.after(function() {
++spun;
enlarge_blade();
title.text('spun ' + spun + ' times');
});
};
// Pre-enlarge the first (yellow) rect
enlarge_blade();
/* make rectangle jump and change color on mouse over */
spin.addEventListener('click', function() {
angle += rotation
spin_anim();
})
Demo here
I see you're using svg.js. I don't know how it treats transforms internally. But in any case. To scale an element, you typically use its center point as a reference. Therefore you should find the center point of each rect and scale it using that point. (I assume svg.js performs the required translation internally).

How to drag a DIV so its width and height are negative values?

I'm a bit stumped here. I am developing a feedback utility that will allow the user to "draw" boxes on a web page to highlight problem areas. Right now I have an overlay DIV that fills the screen and jQuery allows you to draw red outlined DIVs by clicking and dragging.
Here is the JS:
{
var $feedbackOverlay = jQuery('#feedbackOverlay');
var $original = { top: 0, left:0 };
$feedbackOverlay.bind('mousedown', function (e)
{
jQuery('<div id="currentHighlight"></div>')
.css('width', '1px')
.css('height', '1px')
.css('border', 'solid 3px #ff0000')
.css('border-radius', '5px')
.css('position', 'absolute')
.css('left', e.pageX)
.css('top', e.pageY)
.css('z-index', '8000001')
.appendTo('body');
$original = { top: e.pageY, left: e.pageX };
});
$feedbackOverlay.bind('mousemove', function (e)
{
var $currentHighlight = jQuery('#currentHighlight');
if ($currentHighlight.length > 0)
{
var $pos = { top: e.pageY, left: e.pageX };
if($pos.top < $original.top) $currentHighlight.css('top', $pos.top);
if ($pos.left < $original.left) $currentHighlight.css('left', $pos.left);
$currentHighlight.height(Math.abs($pos.top - $original.top));
$currentHighlight.width(Math.abs($pos.left - $original.left));
}
});
$feedbackOverlay.bind('mouseup', function (e)
{
var $currentHighlight = jQuery('#currentHighlight');
$currentHighlight.removeAttr('id');
});
var $feedbackInstructions = jQuery('#feedbackInstructions');
$feedbackInstructions.fadeIn(1000, function ()
{
setTimeout(function ()
{
$feedbackInstructions.fadeOut(1000);
}, 3000);
});
$feedbackOverlay.height(jQuery(document).height());
});
Here is a jsFiddle for the above:
http://jsfiddle.net/Chevex/RSYTq/
The problem is that I can't drag the boxes up or left. The first click puts the top left corner where the mouse clicked. After that subsequent dragging will change the width of the box. Letting go of the mouse completes the box and you may then start drawing another one. If you try to drag the DIV left or up while drawing it's width will remain at 0 but won't go negative.
Here you can find working solution: http://jsfiddle.net/RSYTq/34/
Something like this will get you closer to what you want: http://jsfiddle.net/RSYTq/18/
Doesn't quite handle move up and to the left and then switching to moving down and to the right quite right yet but it gives you the idea.
There's no such thing a a negative width - these are not coorindinates. You need to reposition and recalculate the corner positions relative to the corner that's not being moved.
Sounds like you need to check if the click origin (x,y) is > than the current mouse position, and then swap which one you use for the CSS top-left.
You would need to track the original start point somewhere (variables, data attributes on #currentHighlight, wherever you want), and check for width or height < 0. When so, set the #currentHighlight left/top CSS to be offset by original + (e.pageX - $currentHighlight.position().left) (for example). Then set the #currentHighlight width/height to the same difference (but positive: (e.pageX - $currentHighlight.position().left) * -1).

Categories