Is there any way to animate jsplumb connecting lines as they are being drawn? I want to have an animation, instead of just a line appearing.
I call jsPlumb.connect to draw the line upon clicking a div, like this
$("#manchester").on('click', function() {
jsPlumb.connect({source: "manchester", target: "paris"});
});
First we need to bind an event whenever a connection has been made in order to animate the newly created connection:
jsPlumb.bind("jsPlumbConnection", function(ci) {
new animateConn(ci.connection); //call the animate function for the newly created function
}
Now in the animation function just update the position of connection overlay to get the animation. Before doing make sure that you add overlay to your connections:
jsPlumb.connect({
source: "manchester", target: "paris",
overlays:[
"Arrow",
[ "Label", { location:0.45, id:"arrow" } ]
]
});
Now the animateConn function:
var interval = null;
animateConn = function(conn) {
var arrow = conn.getOverlay("arrow");
interval = window.setInterval(function() {
arrow.loc += 0.05;
if (arrow.loc > 1) {arrow.loc = 0;}
try{
conn.repaint(); // writing in try block since when connection is removed we need to terminate the function for that particular connection
}catch(e){stop();}
}, 100);
},
stop = function() {
window.clearInterval(interval);
};
To customise the overlay refer the API DOC.
Related
I am using the Raphael plugin for the first time and so far I managed to create a map of Germany and to outline all different regions inside. I found out how to bind mouse-over effects, so when I hover over a region its color changes. Everything looks fine until the moment when I want to trigger the same mouse-over effect from outside the map. There is a list of links to all the regions and each link should color its respective geographical position (path) on the map when hovered. The problem is that I don't know how to trigger the mouse-over effect from outside.
This is the reference guide I used for my code: Clickable France regions map
This is my map initialization:
var regions = [];
var style = {
fill: "#f2f2f2",
stroke: "#aaaaaa",
"stroke-width": 1,
"stroke-linejoin": "round",
cursor: "pointer",
class: "svgclass"
};
var animationSpeed = 500;
var hoverStyle = {
fill: "#dddddd"
}
var map = Raphael("svggroup", "100%", "auto");
map.setViewBox(0, 0, 585.5141, 792.66785, true);
// declaration of all regions (states)
....
var bayern = map.path("M266.49486,..,483.2201999999994Z");
bayern.attr(style).data({ 'href': '/bayern', 'id': 'bayern', 'name': 'Bayern' }).node.setAttribute('data-id', 'bayern');
regions.push(bayern);
This is where my "normal" mouse effects take place:
for (var regionName in regions) {
(function (region) {
region[0].addEventListener("mouseover", function () {
if (region.data('href')) {
region.animate(hoverStyle, animationSpeed);
}
}, true);
region[0].addEventListener("mouseout", function () {
if (region.data('href')) {
region.animate(style, animationSpeed);
}
}, true);
region[0].addEventListener("click", function () {
var url = region.data('href');
if (url){
location.href = url;
}
}, true);
})(regions[regionName]);
}
I have a menu with links and I want to bind each of them to the respective region, so that I can apply the animations, too.
$("ul.menu__navigation li a").on("mouseenter", function (e) {
// this function displays my pop-ups
showLandName($(this).data("id"));
// $(this).data("id") returns the correct ID of the region
});
I would appreciate any ideas! Thanks in advance!
I figured out a way to do it. It surely isn't the most optimal one, especially in terms of performance, but at least it gave me the desired output. I would still value a better answer, but as of right now a new loop inside the mouse-over event does the job.
$("ul.menu__navigation li a").on("mouseenter", function (e) {
// this function displays my pop-ups
showLandName($(this).data("id"));
// animate only the one hovered on the link list
var test = '/' + $(this).data("id");
for (var regionName in regions) {
(function (region) {
if (region.data('href') === test) {
region.animate(hoverStyle, animationSpeed);
}
})(regions[regionName]);
}
});
I'm having problems, trying to display the mouse position x/y when they click on an image, im using one of the click on and image example that phaser provides.
here is the code
var game = new Phaser.Game(800, 500, Phaser.AUTO, 'phaser-example', { preload: preload, create: create });
var text;
var counter = 0;
function preload () {
// You can fill the preloader with as many assets as your game requires
// Here we are loading an image. The first parameter is the unique
// string by which we'll identify the image later in our code.
// The second parameter is the URL of the image (relative)
game.load.image('Happy-face', 'happy.png');
}
function create() {
// This creates a simple sprite that is using our loaded image and
// displays it on-screen and assign it to a variable
var image = game.add.sprite(game.world.centerX, game.world.centerY, 'Happy-face');
// Moves the image anchor to the middle, so it centers inside the game properly
image.anchor.set(0.5);
// Enables all kind of input actions on this image (click, etc)
image.inputEnabled = true;
this.position = new Phaser.Point();
text = game.add.text(250, 16, '', { fill: '#ffffff' });
image.events.onInputDown.add(listener, this);
}
function listener () {
counter++;
text.text = "Position x/y " + counter + "!";
}
if you want x and y position o f input
game.input.x;
game.input.y;
if you want for mouse specifically
game.input.mousePointer.x;
game.input.mousePointer.y;
the listener function will be like
function listener () {
counter++;
text.text = game.input.mousePointer.x +"/"+game.input.mousePointer.y + counter + "!";
}
Just to add that the listener function will be sent 2 parameters: sprite and pointer. So you can do:
function listener (sprite, pointer) {
var x = pointer.x;
var y = pointer.y;
...
}
This will be the most accurate method to use as it accounts for multi-touch devices, where-as accessing input.x/y directly doesn't, it only contains the most recent touch event coordinates (which in a mouse only environment is fine, but not anywhere else).
Using the Google Earth plugin, I want to be able to allow the user to select placemarks on the ground while the camera is moving, but am not sure how this is possible. It seems that when you call setAbstractView(), even with the flyToSpeed set to SPEED_TELEPORT, the Google Earth plugin ignores any mouse down events except for those to the GEGlobe.
Here's the code, altered slightly (from http://code.google.com/apis/ajax/playground/#draggable_placemark) to illustrate my issue:
var ge;
var placemark;
var dragInfo = null;
var la;
var lat = 37;
var lon = -122;
google.load("earth", "1");
function init() {
google.earth.createInstance('map3d', initCallback, failureCallback);
}
function tick() {
la.set(lat, lon,
0, // altitude
ge.ALTITUDE_RELATIVE_TO_GROUND,
0, // heading
0, // straight-down tilt
5000 // range (inverse of zoom)
);
ge.getView().setAbstractView(la);
lon = lon + 0.00000001;
}
function initCallback(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
// add a navigation control
ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
// add some layers
ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);
// create the placemark
placemark = ge.createPlacemark('');
var point = ge.createPoint('');
point.setLatitude(lat);
point.setLongitude(lon);
placemark.setGeometry(point);
// add the placemark to the earth DOM
ge.getFeatures().appendChild(placemark);
// look at the placemark we created
la = ge.createLookAt('');
placemark.setName('Drag Me!');
ge.getOptions().setFlyToSpeed(ge.SPEED_TELEPORT);
tick();
// Comment this next line out and the drag works as expected.
google.earth.addEventListener(ge, "frameend", tick);
// listen for mousedown on the window (look specifically for point placemarks)
google.earth.addEventListener(ge.getWindow(), 'mousedown', function(event) {
console.log("target type = " + event.getTarget().getType());
if (event.getTarget().getType() == 'KmlPlacemark' &&
event.getTarget().getGeometry().getType() == 'KmlPoint') {
//event.preventDefault();
var placemark = event.getTarget();
dragInfo = {
placemark: event.getTarget(),
dragged: false
};
}
});
// listen for mousemove on the globe
google.earth.addEventListener(ge.getGlobe(), 'mousemove', function(event) {
if (dragInfo) {
event.preventDefault();
var point = dragInfo.placemark.getGeometry();
point.setLatitude(event.getLatitude());
point.setLongitude(event.getLongitude());
dragInfo.dragged = true;
}
});
// listen for mouseup on the window
google.earth.addEventListener(ge.getWindow(), 'mouseup', function(event) {
if (dragInfo) {
if (dragInfo.dragged) {
// if the placemark was dragged, prevent balloons from popping up
event.preventDefault();
}
dragInfo = null;
}
});
document.getElementById('installed-plugin-version').innerHTML =
ge.getPluginVersion().toString();
}
function failureCallback(errorCode) {
}
If you comment out line 56, where tick() is called at each frameend, everything works as in the unaltered code: you can successfully drag the place mark. But when line 56 is in, you can't. So the problem is really with setAbstractView keeping mousedown events from propagating to either the globe or whatever placemark or feature was being clicked.
Any ideas? Is there a workaround for this?
The issue isn't caused by the setAbstractView method, it is caused because of the repeated calls to the tick method via framend.
To explain, you have set up the tick method as an event handler for the frameend event.
Then the tick method updates the view immediately, triggering the frameend event, ad infinitum ...
This pattern causes an issue with the browser message loop, in effect it is blocking the other drag events. Think of it like a very tight loop that is causing a deadlock. To work it you can use setTimeout with a value of 0 to execute the code. This way the animation won't be processed until all other pending drag messages are processed.
The key part is a the modification to your tick() method.
function tick() {
// prevent deadlock
setTimeout(function () {
la.set(lat, lon, 0, ge.ALTITUDE_RELATIVE_TO_GROUND, 0, 0, 5000);
ge.getView().setAbstractView(la);
lon += 0.00001;
}, 0);
};
Here, I made a fully working example for you http://jsfiddle.net/fraser/JFLaT/
I tested it and it is working in Chrome, IE, Firefox on Windows 8 and Chrome, Safari, Firefox on OSX.
currently this is causing the (image) fadeout function to end, and then the fade in function fires. i need the images to crossfade and the opacity of each image to overlap. im having trouble getting this work. thoughts?
_initFade: function () {
this._timer = Y.later(this._intervalDuration, this, this._startPeriod, [], false);
},
_startPeriod: function () {
this._timer = Y.later(this._intervalDuration, this, this._fadeOut, [], true);
this._fadeOut();
},
_fadeOut: function(){
var host = this.get('host');
this._animOut.set('node', host._getCurrentBlock());
this._animOut.once('end', this._fadeIn, this);
this._animOut.run();
},
_fadeIn: function(){
var host = this.get('host'),
blocks = host.get('blocks'),
index = host.get('index');
index = host._moveIndex(host._getNextIndex());
var nextBlock = blocks.item(index);
this._transparent(nextBlock);
host.syncUI();
this._animIn.set('node', nextBlock);
this._animIn.run();
},
YUI doesn't support multiple animations which run in sync. But have a look at the 'tween' event of Y.Anim. It is called for every frame of the animation. So you can fade one image using the animation and adjust the opacity of the second image during the tween event.
For example, I use the tween event to animate multiple items simultaneously:
var someNode = Y.Node.create("<div></div>"); // invisible div to animate
Y.one(document.body).appendChild(someNode);
var anim = new Y.Anim({
node: someNode,
duration: 0.25,
from: { color: 'red' },
to: { color: 'white' }
});
anim.on('tween', function(event){
Y.StyleSheet().set('input.text.error', { backgroundColor: someNode.getStyle('color') });
// other animations
});
I am making a simple slider that works by changing the src attribute of an img tag and the attributes of anchor tags. This is what I have come up with so far:
(function($){
var slides = [
'http://placehold.it/801x350',
'http://placehold.it/802x350',
'http://placehold.it/803x350'
],
titles = [
'Title 1',
'Title 2',
'Title 3'
],
links = [
'http://test1.com',
'http://test2.com',
'http://test3.com'
],
image = $('#stretch-img'),
anchor = $('.featured-title>h2>a');
var interval = setInterval(function() {
image.attr('src', slides[0]);
anchor.attr('href', links[0]);
anchor.html(titles[0]);
}, 3000);
})(jQuery);
I want the interval to loop through the arrays continuously with a simple fade effect. What can be the best way to do this or any way to do this really, coz I've got none.
Thanks!
I appreciate all the help.
To loop through your array you can set a current-position-variable and a variable that saves the length of the array:
var current = 0,
length = slides.length,
interval = setInterval(function() {
image.attr('src', slides[current]);
anchor.attr('href', links[current]).html(titles[current]);
current++;
if (current >= length) {
current = 0;
}
}, 3000);
Then to fade you can fade-out, change the source, then fade-back-in:
image.fadeOut(500, function () {
image.attr('src', slides[current]).fadeIn(500);
anchor.attr('href', links[current]).html(titles[current]);
current++;
if (current >= length) {
current = 0;
}
});
This can lead to the image not quite being loaded when the fadeIn(500) kicks-in, which can be fixed by using an event handler attached to the load event for the image element:
var image = $('#stretch-img').on('load', function () {
image.fadeIn(500);
});
Then you can remove the fadeIn(500) from the interval function since it will fire when the image has loaded. The load event will fire whenever the source of the image changes and the new source finishes loading.
Note that .on() is new in jQuery 1.7 and is the same as .bind() in this case.