Raphael, animation of points - javascript

I have a function which displays lines (x and y coordinates) based on the time information. The x and y coordinates specify the position of the drawn points whereas time represents the timestamps (in milliseconds) of the respective points.
Currently, there is a function which displays line as below
<script type="text/javascript" src="https://raw.github.com/DmitryBaranovskiy/raphael/master/raphael-min.js"></script>
<script type="text/javascript">
function drawLine(points) {
var paths = ['M ' + points[0].x + ' ' + points[0].y];
for (var i = 1; i < points.length; i++) {
var p = points[i];
paths.push(paths[i - 1] + ' L ' + p.x + ' ' + p.y);
}
var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
var line = paper.path(paths[0]);
var next = 1;
function animate() {
if (paths[next]) {
duration = points[next].t - points[next - 1].t
line.animate({ path: paths[next] }, duration, 'linear', animate);
next++;
}
}
animate();
}
</script>
And the function can be called using associative arrays as follows:
drawLine([
{ x: 0, y: 0, t: 0 },
{ x: 100, y: 230, t: 1520 },
{ x: 210, y: 290, t: 3850 },
{ x: 150, y: 200, t: 5060 },
]);
The question is, how can I modify this function to display points and not the lines?

You can add a drawPoint method, which will take an object with x and y properties
function drawPoint(point) {
paper.circle(point.x, point.y, 5).attr('fill', 'red');
};
Then call it from your animate function, before the points[next] comparison
drawPoint(points[next - 1]);
Here's the JSFiddle http://jsfiddle.net/jaimem/2krgN/
If you don't want the lines, then you don't need paths
function drawPoints(points){
var paper = new Raphael('canvas_container', 500, 500),
idx = 0;
function animate(){
if(points[idx]){
var currP = points[idx],
prevP = points[idx - 1],
d = currP.t - (prevP ? prevP.t : 0 );
paper.circle(currP.x, currP.y, 1)
.attr('fill', 'red')
.animate({r:5}, d, animate);
idx++
}
}
animate();
}
The recursive animate callback might be a little difficult to understand/read, so might just want to use a setTimeout. Also you can pass a string with the id of an element to the Raphael constructor and the library will find the DOM node for you.
JS Fiddle: http://jsfiddle.net/jaimem/Q5G5y/2/

Related

Algorithm for SigmaJS node positioning

I'm trying to create a visual graph of points in a readable and not messy way,
I have ids which represents the nodes and contact that represents the child nodes of the parent node.
I have manage to plot them all and connect them correctly based on parent-child relationship but my problem now is to actually position them to look visually okayish.
my code so far is this: (don't mind the value of cx, cy as thats where I'm stuck with)
var json_data = JSON.parse('[{"id":1,"contact":[{"id":2,"contact":[{"id":5},{"id":6},{"id":7}]},{"id":3,"contact":[{"id":8},{"id":9},{"id":10}]},{"id":4,"contact":[{"id":11},{"id":12},{"id":13}]}]}]');
var g = {
nodes: [],
edges: []
};
var gx = 0, gy = 0;
processLevel(json_data, gx, gy);
function processLevel(data, cx, cy, parent = null) {
console.log("Function Called: data length = " + data.length);
console.log("cy = " + cy);
for(var x = 0; x < data.length; x++){
console.log(data[x].id);
cx = x;
console.log("cx = " + cx);
g.nodes.push({
id: 'n' + data[x].id,
label: 'Node ' + data[x].id,
x: cx*cy,
y: cy,
size: 1,
color: '#FF2D00'
});
if(parent) {
g.edges.push({
id: 'e-' + parent + '-' + data[x].id,
source: 'n' + parent,
target: 'n' + data[x].id,
size: 1,
color: '#000'
});
}
if(typeof data[x].contact !== 'undefined') {
cy++;
processLevel(data[x].contact, cx, cy, data[x].id);
}
}
}
// Instantiate sigma:
s = new sigma({
graph: g,
container: 'graph-container'
});
desirable output would be something like this:

How to highlight particular region in horizontal way in dygraph and how to create dynamic graph

i need to highlight y value example 20 to -10 and -30 to -45 in y axis. permanently with some color with opacity 50%, how to do.,
in this example how to add external csv file to this following code. Pls Guide me
var orig_range;
window.onload = function(){ var r = [];
var arr = ["7/13/2015 0:15:45",45,"7/13/2015 0:30",5,"7/13/2015 0:45",100,"7/13/2015 1:00",95,"7/13/2015 1:15",88,"7/13/2015 1:30",78];
for (var i = 0; i < arr.length; i++) {
r.push([ new Date(arr[i]),arr[i+1]
]);
i++;
}
orig_range = [ r[0][0].valueOf(), r[r.length - 1][0].valueOf() ];
g2 = new Dygraph(
document.getElementById("div_g"),
r, {
rollPeriod: 7,
animatedZooms: true,
// errorBars: true,
width: 1000,
height: 500,
xlabel: 'date',
ylabel: 'Pressure',
}
);
var desired_range = null;};
function approach_range() {
if (!desired_range) return;
// go halfway there
var range = g2.xAxisRange();
if (Math.abs(desired_range[0] - range[0]) < 60 &&
Math.abs(desired_range[1] - range[1]) < 60) {
g2.updateOptions({dateWindow: desired_range});
// (do not set another timeout.)
} else {
var new_range;
new_range = [0.5 * (desired_range[0] + range[0]),
0.5 * (desired_range[1] + range[1])];
g2.updateOptions({dateWindow: new_range});
animate();
}
}
function animate() {
setTimeout(approach_range, 50);
}
function zoom(res) {
var w = g2.xAxisRange();
desired_range = [ w[0], w[0] + res * 1000 ];
animate();
}
function reset() {
desired_range = orig_range;
animate();
}
function pan(dir) {
var w = g2.xAxisRange();
var scale = w[1] - w[0];
var amount = scale * 0.25 * dir;
desired_range = [ w[0] + amount, w[1] + amount ];
animate();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/1.1.0/dygraph-combined-dev.js"></script>
<div id="div_g"></div>
<div id="output"></div>
<b>Zoom:</b>
hour
day
week
month
full
<b>Pan:</b>
left
right
i'm trying to convert graph to dynamic graph data from csv file
var data = ["te1.csv"];
g2 = new Dygraph(document.getElementById("div_g"), data,
{
drawPoints: true,
showRoller: true,
labels:['date','depth'],
});
setInterval(function() {
data.push([data]);
g2.updateOptions( { 'file': data } );
}, 1000);
i have seen example but i dont know how to link my csv file with dynamic dygraph pls guide me
This example does something extremely similar to what you want: it highlights a specific range on the x-axis. To adapt it, you'd do something like this:
new Dygraph(data, div, {
underlayCallback: function (canvas, area, g) {
var bottom = g.toDomYCoord(highlight_start);
var top = g.toDomYCoord(highlight_end);
canvas.fillStyle = "rgba(255, 255, 102, 1.0)";
canvas.fillRect(area.x, top, area.w, bottom - top);
}
})

Tweened Kinetic.js shape doesn't fire most of clicks

Purpose
I'm making a simple "shoot the word" game, where user needs to click on some moving rectangles with words to "shoot" them.
Problem
So i create some objects and move them using simple kinetic.js tweening.
Word creation
function createWord(value){
//here comes some word object construction
var wordGroup = new Kinetic.Group({
x: 0,
y: 0
});
var padding = 10;
wordGroup.label = new Kinetic.Text({
x: padding,
y: padding,
text: value,
fontFamily: 'Times New Roman',
fontSize: 30,
fill: 'white'
});
wordGroup.tag = new Kinetic.Rect({
x: 0,
y: 0,
width: wordGroup.label.width() + (padding << 1),
height: wordGroup.label.height() + (padding << 1),
fill: 'black',
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: {x:10,y:20},
shadowOpacity: 0.5,
cornerRadius: 10
});
wordGroup.add(wordGroup.tag);
wordGroup.add(wordGroup.label);
wordGroup.shoot = function(){ //shooting mechanism (simple stop from moving and remove from scene)
wordGroup.tween.pause();
wordGroup.clean();
dropNextWord(); //drops fresh blood! (new word instead of shooted)
}
wordGroup.clean = function(){ //remove from scene and set it free to drop again
wordGroup.remove();
wordGroup.isActive = false;
}
wordGroup.move = function(callback){ //animates word
wordLayer.add(wordGroup);
moveToSide(wordGroup, callback); //calls moving function
}
wordGroup.on('click', function(e){
wordGroup.shoot();
});
return wordGroup;
}
Tweening part
//move word to opposite side
function moveToSide(word, callback){
var side = Math.random();
var d = 100;
spawnFromSide(word, side); //set random side word position
tweenPosition = {
x: word.x(),
y: word.y()
}
if(side < 0.25){ //left
tweenPosition.x = - d;
} else if(side > 0.25 && side < 0.5){ //right
tweenPosition.x = defaultStageWidth + d;
} else if(side > 0.5 && side < 0.75){ //up
tweenPosition.y = - d;
} else { //down
tweenPosition.y = defaultStageHeight + d;
}
word.tween = new Kinetic.Tween({
node: word,
duration: 4,
easing: Kinetic.Easings.Linear,
x: tweenPosition.x,
y: tweenPosition.y,
onFinish: function(){
word.clean();
callback();
}
});
word.tween.play();
}
But the problem is that click event doesn't fire on large amount of user clicks. As i think, this caused by delayed drawHit() calls inside tweening mechanism, that draws new object position before updating the hit area, so when we shoot object thinking that we hit its current position we miss because its hit area still have the same old position.
Live example
http://jsfiddle.net/hd6z21de/7/
Take a minute on shooting to see this effect in action
Solved this weird behavior by listening canvas touches and check if pointer collide some target word-rect by myself instead of using their own onclick events.
//i listen to canvas because of my app specific, you could simple listen your own layer or even document
$("canvas").bind('click', function(event){
var x = (event.pageX) / stage.scaleX(); //you don't need to divide by scale if your stage isn't scaled as mine does
var y = (event.pageY) / stage.scaleY();
var wordArray = wordGroup.getChildren();
for(var i = 0; i < wordArray.length; i++){ //go through all words and check if we shoot someone (is mouse position included in some word rect)
if(x > wordArray[i].x() &&
y > wordArray[i].y() &&
x < (wordArray[i].x() + wordArray[i].width()) &&
y < (wordArray[i].y() + wordArray[i].height())){
wordArray[i].shoot(); //shoot that word
break;
}
}
}

Javascript: How to call object method on Raphael path?

I have a JavaScript object that includes a number of Raphael paths. (The paths make up a stack of pie charts that all draw on the same paper.) I want each path to trigger an object method when clicked. However, when I click a path, I get "Uncaught TypeError: undefined is not a function" (Chrome for Mac OS). Does anyone know how to do this? Here's a distillation of my code:
// Definition of PieChartStack object
function PieChartStack() {
this.setNodeTree = function (nodeTree) {
this.nodeTree = nodeTree;
...
this.performInitialSetup();
}
this.performInitialSetup = function() {
...
var paper = Raphael("holder", "100%", "100%");
...
paper.customAttributes.segment = function (x, y, r, a1, a2) {
...
return {
path: [["M", x, y], ["l", r * Math.cos(a1), r * Math.sin(a1)], ["A", r, r, 0, +flag, 1, x + r * Math.cos(a2), y + r * Math.sin(a2)], ["z"]],
fill: "hsb(" + clr + ", .75, .8)"
};
};
this.handleSliceTap = function(chartIndex, sliceIndex) {
console.log(chartIndex + " , " + sliceIndex);
}
for (var chartIndex = 0; chartIndex < this.pieCharts.length; chartIndex++) {
...
for (sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) {
...
var path = paper.path().attr({segment: [this.centerX, this.centerY, 1, start, start + val], stroke: "#fff"});
// PROBLEM HERE ======================================
path.click(
function (e) {
this.handleSliceTap(chartIndex, sliceIndex);
}
);
//====================================================
}
}
}
return this;
}
Teemu got it -- "this" in this context is the path, not the PieChartStack. Fixed by creating a new var: var self = this -- and then doing it like so:
self.handleSliceTap(chartIndex, sliceIndex);

Please explain this javascript comma syntax commonly used to define Dragging RaphaelJs

Here is the "dragger" defined in the raphaeljs graffle example.
var dragger = function () {
this.ox = this.type == "rect" ? this.attr("x") : this.attr("cx");
this.oy = this.type == "rect" ? this.attr("y") : this.attr("cy");
this.animate({"fill-opacity": .2}, 500);
},
move = function (dx, dy) {
var att = this.type == "rect" ? {x: this.ox + dx, y: this.oy + dy} : {cx: this.ox + dx, cy: this.oy + dy};
this.attr(att);
for (var i = connections.length; i--;) {
r.connection(connections[i]);
}
r.safari();
},
up = function () {
this.animate({"fill-opacity": 0}, 500);
},
r = Raphael("holder", 640, 480),
connections = [],
shapes = [ r.ellipse(190, 100, 30, 20),
r.rect(290, 80, 60, 40, 10),
r.rect(290, 180, 60, 40, 2),
r.ellipse(450, 100, 20, 20)
];
Am I right that:
That move, up, r, connections and shapes are INDEPENDENT variables? I.e. NOT methods/ attributes of dragger?
This is just a sequential definition of variables at an equivalent scope?
Are move, up, etc. considered to have been declared using the var keyword?
Thanks for the help. Love and peace.
This is just like a long series of var statements.
Similar, and easier to read:
var a = 1, b = 2, c = 3;
In this case I definitely would NOT use this syntax, and would instead use a separate line for each variable. It's really hard to read as is.
In short: yes, you are right on both counts. This is exactly the same as
var dragger = ...;
var move = ...;
var up = ....;
...
except it's a pain to read. The extra commas hiding between declarations are what tie the whole thing together into the var statement.

Categories