I am looking for the simplest and more straightforward way for making a looping/repeating puslating background of some element.
E.g. if I have a circle:
var filler = {
'fill': 'white',
'stroke': 'white',
'stroke-width': '0'
}
var fillerHover = {
'fill': '#b6def1',
'stroke': '#b6def1',
'stroke-width': '0',
'cursor': 'pointer'
}
circle.hover(function() {
circle.animate(fillerHover, 500);
},
function() {
circle.animate(filler, 500);
}
);
This code above is working well, however it animates the transition only once and I would like to make a repeating loop as long as I am hovering over the circle.
And I want to loop the background when I have cursor on the circle from filler to fillerHover until I go out with the cursor.
How to create such loop in the simplest way?
You could add a callback to the animation that starts it again: http://raphaeljs.com/reference.html#Element.animate
Don't do it in a setInterval, that will f**k up the framerate!
Don't even use requestAnimationFrame. You don't know when it will trigger animation. The only 'safe' way to do this is let Raphael tell you when the animation finished (via the callback option) to start the next animation.
Something like:
fillerHover.callback = mouseOver;
function mouseOver() {
circle.animate(fillerHover, 500);
}
circle.hover(
mouseOver,
function() {
circle.animate(filler, 500);
}
);
Mix that with your current code =) You know what I mean.
EDIT: This looks like it: http://jsfiddle.net/rudiedirkx/j9XyX/6/show/
Related
What I'm trying to achieve: when my mouse is moving then do this, but when it stops moving for like half a second then do that, but when it starts to move again then do that.
This is my temporary jQuery:
$(document).ready(function() {
$('.test').mouseenter(function(){
$(this).mousemove(function(){
$(this).css({
'background-color' : '#666',
'cursor' : 'none'
});
});
});
$('.test').mouseout(function(){
$(this).css({
'background-color' : '#777',
'cursor' : 'default'
});
});
});
And I have absolutely no idea how to do that, basically my code does this: when you enter an element with a mouse and your mouse is moving inside that element then apply this CSS and when your mouse leaves the element then apply this CSS, but when mouse is inside that element and it stops moving for some period of time then do this <- I can't figure the last bit out.
I understood that you want to detect the mouse movements over a particular element.
To achieve this, you need to use the mousemove event... There is no mousefroze event, sadly!
So you will use a setTimeout() and will constantly clear its callback while the mouse moves. Since that event fires multiple times on a single slight movement, you can set the delay quite tight. So it should be accurate.
The setTimeout callback will execute only when the mouse will stop moving. And that is the whole "trick".
About delays... I think that 100 ms is the lowest accurate value. Less than that will create flickering on "slow" user moves.
The mouseenter is not really usefull here, because it is overridden by the mousemove event right after (because when the mouse enters... it also moves!). But the mouseleave or mouseout is really usefull to restore the element's original state and clear the timeout too... Because the mouse won't be moving over your element does'nt mean it doesn't move at all. So you have to clear that when leaving.
$(document).ready(function() {
var test = $('#test');
var moveTimer;
test.on("mouseout",function(){
$(this).css({
'background-color' : 'white',
}).text("");
clearTimeout(moveTimer);
});
test.on("mousemove",function(){
console.log("I'm moving!");
clearTimeout(moveTimer);
moveTimer = setTimeout(function(){
console.log("I stopped moving!");
test.css({
'background-color' : 'red',
}).text("The mouse is not moving.");
},100)
$(this).css({
'background-color' : 'blue',
}).text("Movement detected...");
});
});
#test{
margin:50px;
border:2px solid black;
height:200px;
width:200px;
cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test"></div>
CodePen
Sounds like you're looking for timeouts. In a similar project, I used something like this:
var timer;
function active() {
// Apply active styles
}
function inactive() {
// Apply inactive styles
}
$('.test').mousemove(function(){
active(); // Apply active styles
clearTimeout(timer); // Reset the timer
timer = setTimeout(out, 500);
});
Once you move the mouse over the area, that launches a timer that resets every mouse move. If the timer is ever allowed to expire, the user's gone inactive and we run whatever code we like.
So I was just googling. This is the answer:
$(document).ready(function() {
var countdown;
$('.test').hover(function() {
setTimeout(function(){
$('.test').css({
'background-color' : '#666',
'cursor' : 'none'
});
cursor();
}, 2000);
}, function(e){
$('.test').css({
'background-color' : '#777',
'cursor' : 'default'
});
});
$('.test').mousemove(function() {
$('.test').css({
'background-color' : '#777',
'cursor' : 'default'
});
cursor();
});
function cursor() {
countdown = setTimeout(function() {
$('.test').css({
'background-color' : '#666',
'cursor' : 'none'
});
}, 2000);
}
});
});
This may deviate from your current code, but I think CSS is more appropriate here than JavaScript.
.test {
background-color:#666;
}
.test:hover {
background-color:#777;
cursor:none;
}
These lines of CSS should perform the exact same thing without the complication. Note that in your example, for every pixel the mouse moves, the css is set once more. And since you are not removing the event handler on mouse out, the event is actually ran multiple times.
I have defined a path with opacity 0 that includes within several elements. The purpose of that is because when mouse is over that path, the element appears (or disappear if we left the path). My problem is since the path is on top of the canvas, I cannot click on those elements and expect to be able to handle the event.
What would be the best strategy to deal with that?
I tried to put the path on back(); but when I hover over an element, it's like if I left the path.
I tried to put the element on top, but same result as before.
Using the function ispointinsidepath() and then getting the coordinates of the point I clicked seems fastidious, since element size are not constant.
You can put handlers on each of the elements, and deal with it that way. Might even be slightly easier if using Snap rather than Raphael as you can use groups then (and not need multiple event handlers), but assuming Raphael is a requirement you could do this...
var r = paper.rect(50,50,200,200).attr({ fill: 'blue', opacity: '0'}).hover( hoverover, hoverout )
var c1 = paper.circle(100,100,30).attr({ fill: 'red' }).click( clickFunc ).hover( hoverover, hoverout)
var c2 = paper.circle(200,200,30).attr({ fill: 'blue' }).click( clickFunc ).hover( hoverover, hoverout )
function hoverover() { r.attr({ opacity: 1 } ) }
function hoverout() { r.attr({ opacity: 0 } ) }
function clickFunc() { alert('clicked')}
jsfiddle
I'm developing some page when I use Raphael liblary to draw some items.
my App
So my problem is in that when I'm moving to some rect it growing up but when my mouse is on text which is positioning on my rect, it loss his hover. You can see it on my app example.
var paper = new Raphael(document.getElementById('holder'), 500, object.length * 100);
drawLine(paper, aType.length, bType.length, cType.length, cellSize, padding);
process = function(i,label)
{
txt = paper.text(390,((i+1)* cellSize) - 10,label.devRepo)
.attr({ stroke: "none", opacity: 0, "font-size": 20});
var a = paper.rect(200, ((i+1)* cellSize) - 25, rectWidth, rectHeight)
.hover(function()
{
this.animate({ transform : "s2"}, 1000, "elastic");
this.prev.animate({opacity: 1}, 500, "elastic");
this.next.attr({"font-size" : 30});
},
function()
{
this.animate({ transform : "s1" }, 1000, "elastic");
this.prev.animate({opacity: 0}, 500);
this.next.attr({"font-size" : 15});
});
}
I have tried e.preventDefault(); on hover of this.next and some other solutions but it's doesn't work.
Any help would be appreciated.
Most people will suggest you place a transparent rectangle over the box and the labels and attach the hover functions to that instead. (If memory serves, you have to make the opacity 0.01 instead of 0 to prevent the object from losing its attached events.) This works fine, but I don't love this solution; it feels hacky and clutters the page with unnecessary objects.
Instead, I recommend this: Remove the second function from the hover, making it functionally a mouseover function only. Before you draw any of the rectangles and labels, make a rectangular "mat" the size of the paper. Then, attach the function that minimizes the label as a mouseover on the mat. In other words, you're changing the trigger from mousing out of the box to mousing over the area outside of it.
I left a tiny bit of opacity and color on the mat to be sure it's working. You can just change the color to your background color.
var mat = paper.rect(0, 0, paper.width, paper.height).attr({fill: "#F00", opacity: 0.1});
Now, you want to make a container for all the rectangles so you can loop through them to see which need to be minimized. I made an object called "rectangles" that contains the objects we're concerned with. Then:
mat.mouseover(function () {
for (var c = 0; c < rectangles.length; c += 1) {
//some measure to tell if rectangle is presently expanded
if (rectangles[c].next.attr("font-size")) {
rectangles[c].animate({
transform : "s1"
}, 1000, "elastic");
rectangles[c].prev.animate({opacity: 0}, 500);
rectangles[c].next.attr({"font-size" : 15});
}
}
});
Then I just removed the mouseout function from the individual rectangles.
jsBin
To be clear, this will have some downsides: If people run the mouse around really fast, they can expand several rectangles at the same time. This is remedied as soon as the mouse touches the mat. I think the functionality looks pretty nice. But the invisible mats is always an option.
I wrote a small extension to Raphael - called hoverInBounds - that resolves this limitation.
Demo: http://jsfiddle.net/amustill/Bh276/1
Raphael.el.hoverInBounds = function(inFunc, outFunc) {
var inBounds = false;
// Mouseover function. Only execute if `inBounds` is false.
this.mouseover(function() {
if (!inBounds) {
inBounds = true;
inFunc.call(this);
}
});
// Mouseout function
this.mouseout(function(e) {
var x = e.offsetX || e.clientX,
y = e.offsetY || e.clientY;
// Return `false` if we're still inside the element's bounds
if (this.isPointInside(x, y)) return false;
inBounds = false;
outFunc.call(this);
});
return this;
}
Hi! I really try to find a topic related to my issue here, but I had no luck...
Some simple code: I have two divs, placed in the same position -
<div id="fader1" style="display:inline-block;position:absolute;background-image:url(images/fader1.png);opacity:1;width:296px;height:435px;margin:-215px 50px -20px"></div>
<div id="fader2" style="display:inline-block;position:absolute;background-image:url(images/fader2.png);opacity:0;width:296px;height:425px;margin:-215px 50px -20px"></div>
The idea is when the mouse passes over the div "fader1", the opacity changes to 0, and the opacity of fader2 changes to 1. And turn back like the beginning if I put the cursor out of the div.
I've tried to achieve this with mootools but I'm now in a dead-end.
Mootools Demos have the example of Fx.Morph like this:
$('myElement').set('opacity', 0.5).addEvents({
mouseenter: function(){
// This morphes the opacity and backgroundColor
this.morph({
'opacity': 0.6,
'background-color': '#E79D35'
});
},
mouseleave: function(){
// Morphes back to the original style
this.morph({
opacity: 0.5,
backgroundColor: color
});
}
});
As you can see, I can only manage ONE element (this.morph). I try to put other element like: "('fader1').morph" with no results... But I think that I'm doing it wrong.
I really appreciate any help you can give me to achieve this in mootools. Regards!
you should read the manual and not copy/paste from examples.
$('myElement').set('opacity', 0.5).addEvents({
mouseenter: function(){
// This morphes the opacity and backgroundColor
this.morph({
'opacity': 0.6,
'background-color': '#E79D35'
});
}
});
in the above function, the scope this refers to myElement. if you need to reference a different element, then simply do so.
(function(){
var other = $('myOtherElement').set('moprh', {
link: 'cancel'
}); // save a reference and set link to cancel existing morphing
$('myElement').set('opacity', 0.5).addEvents({
mouseenter: function(){
// This morphes the opacity and backgroundColor
other.morph({
'opacity': 0.6,
'background-color': '#E79D35'
});
},
mouseleave: function(){
// Morphes back to the original style
other.morph({
opacity: 0.5,
backgroundColor: color
});
}
});
}());
read up on what $ (documentid) returns (an element), saving an element into a variable and referencing it later - this is standard javascript.
This morphs just fine but I need it to pause first then morph.
var animate = (function(){
var div = document.getElement('div.es-transition');
if (div){
div.set('morph', {duration: 800, transition: 'quad:out'});
div.pauseFx(1000, 'morph');
div.addClass('hidden');
div.setStyles({'visibility': 'hidden', 'opacity': 0});
div.removeClass('hidden').fade('in');
}
});
window.addEvent('load', animate);
Banging head.
TIA
don't know about pauseFx? this is not standard mootools-core api. it has http://mootools.net/docs/core/Fx/Fx#Fx:pause - which needs to be applied to the instance.
in your case, it makes no sense anyway as you pause before you even run it. which means, use setTimeout or delay. pause is to stop and resume a morph/tween midway. please clarify what you are trying to achieve
also. .set('morph') does not work with .fade() - fade is based on tween options, not morph. the difference between tween and morph is single property vs multiple properties.
if I understand this correctly, you need to rewrite as:
var animate = (function(){
var div = document.getElement('div.es-transition');
if (div){
div.set('tween', {duration: 800, transition: 'quad:out'});
div.addClass('hidden');
div.setStyles({'visibility': 'hidden', 'opacity': 0});
(function(){
div.removeClass('hidden').fade(0, 1);
}).delay(1000);
}
});
window.addEvent('load', animate);