Constant Layout Graph with VivaGraphJS - javascript

I created a graph with VivaGraphJS and everything is well but the graph is moving .there is an example about constantLayout but the problem you should specify for every node a position.
here is the code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="../js/vivagraph.js"></script>
<script type="text/javascript">
function main () {
// create a graph object.
var graph = Viva.Graph.graph();
add nodes and edges to the graph:
graph.addLink(1, 2);
graph.addLink(1, 3);
graph.addLink(1, 4);
var renderer = Viva.Graph.View.renderer(graph);
renderer.run();
}
</script>
<style type="text/css" media="screen">
html, body, svg { width: 100%; height: 100%;}
</style>
</head>
<body onload='main()'>
</body>
</html>
and here is the code about the constant Layout :
<!DOCTYPE html>
<html>
<head>
<title>VivaGraphs constant layout demo page</title>
<script src="../../dist/vivagraph.js"></script>
<script type='text/javascript'>
function onLoad() {
var graph = Viva.Graph.graph(),
nodePositions = [{x : -50, y: 0}, {x : 0, y: -50}, {x : 50, y: 0}], // predefined node positions
layout = Viva.Graph.Layout.constant(graph),
renderer = Viva.Graph.View.renderer(graph, {
layout : layout, // use our custom 'constant' layout
}),
i, nodesCount = nodePositions.length; // convinience variables.
// Add nodes
for(i = 0; i < nodesCount; ++i) {
graph.addNode(i, nodePositions[i]);
}
// and make them connected in cycle:
for (i = 0; i < nodesCount; ++i) {
graph.addLink(i % nodesCount, (i + 1) % nodesCount);
}
// set custom node placement callback for layout.
// if you don't do this, constant layout performs random positioning.
layout.placeNode(function(node) {
// node.id - points to its position but you can do your
// random logic here. E.g. read from specific node.data
// attributes. This callback is expected to return object {x : .. , y : .. }
return nodePositions[node.id];
});
renderer.run();
}
</script>
<style type="text/css" media="screen">
body, html, svg { width: 100%; height: 100%; overflow: hidden; }
</style>
</head>
<body onload="onLoad()">
</body>
Any suggestion !?
I wish I explain well my problem. Thanks

If you want to have dynamic layout, but want to stop animation at some point use renderer.pasue() method.
If you want to have a constant layout, you can add some things in your code to tell it the locations of your nodes. Here's the code you'll need:
function main () {
// create a graph object.
var graph = Viva.Graph.graph(),
nodePositions = [{x : -50, y: 0}, {x : 0, y: -50}, {x : 50, y: 0}, {x: 60, y: 20}],
layout = Viva.Graph.Layout.constant(graph);
for(var i = 1; i < 5; i++) {
graph.addNode(i, nodePositions[i-1]);
}
graph.addLink(1, 2);
graph.addLink(1, 3);
graph.addLink(1, 4);
layout.placeNode(function(node) {
return nodePositions[node.id-1];
});
var renderer = Viva.Graph.View.renderer(graph, { layout:layout });
renderer.run();
}

Related

Using variable font inside WEBGL canvas, p5 js

I have a WEBGL canvas in which I am loading a 3d model. I also have a text in variable font which I create with createP. The problem is that I need the text to be between the background and the 3d model. But I can only have the text in front of the canvas (on top of 3d model). Is there any way I can achieve this?
Ps. Creating the text with text() does not allow me to have variable weight value.
let kalameh;
var cnv;
let img;
function preload(){
img = loadImage('assets/lines.png');
kalameh = loadModel('kalameh.obj');
}
function setup() {
cnv = createCanvas(700, 700, WEBGL);
var x = (windowWidth - width) / 2;
var y = (windowHeight - height) / 2;
cnv.position(x, y);
wordA = createP('my text');
}
function draw() {
background(220, 220, 220);
wordA.style('font-size', '110px');
wordA.style('font-weight', '200');
wordA.style('font-stretch', '200%');
wordA.style('align', 'center');
wordA.position(40,25);
image(img, -1*windowWidth/2, -1*windowHeight/2, windowWidth, windowHeight);
translate (0,0,100);
pointLight(255,255,255, -350,0,400);
pointLight(255,255,255, 350,0,400);
ambientMaterial(255);
noStroke();
scale (0.25);
model(kalameh);
}
You could create two sketches (and thus two canvases) and assign z-index properties of -1 and 1 to make them foreground and background sketches, respectively. You can then sandwich the paragraph element that you created between the two canvases by giving it a z-index of 0. You can then make the foreground sketch transparent by calling clear() at the beginning of the draw loop.
In the code snippet below, the 3D object is in front of the text paragraph, whereas the white square of the "background" is behind the text.
let testP;
new p5(function(p){
p.setup = function() {
const foregroundCanvas = p.createCanvas(400, 400, p.WEBGL);
foregroundCanvas.id("foregroundSketch");
foregroundCanvas.position(0, 0);
p.normalMaterial();
testP = p.createP("In front of background / behind object ")
testP.position(95, 115);
testP.id("sandwichedParagraph")
p.angleMode(p.RADIANS)
}
p.draw = function() {
p.clear();
//drag to move the world.
// p.orbitControl();
p.push();
let rotateAngle = p.sin(p.frameCount/50);
p.rotateX(rotateAngle/2);
p.rotateY(-rotateAngle);
p.rotateZ(rotateAngle);
p.box(200, 100, 40);
p.pop();
}
}, "foregroundSketch");
new p5(function(p){
p.setup = function() {
const backgroundCanvas = p.createCanvas(400, 400);
// backgroundCanvas.parent("wrapper")
backgroundCanvas.position(0, 0);
backgroundCanvas.id("backgroundSketch")
p.noStroke();
}
p.draw = function() {
p.background(200);
let shiftAmount = p.map(p.sin(p.frameCount/60), -1, 1, 80, 310);
p.rect(shiftAmount, 120, 40, 40);
}
}, "backgroundSketch");
html, body {
margin: 0;
padding: 0;
}
/* The sketch with the white square has z-index of -1 (background!) */
#backgroundSketch {
z-index: -1;
position: absolute;
}
/* The <p> has z-index of 0 (sandwiched between both sketches)*/
#sandwichedParagraph {
z-index: 0;
position: absolute;
}
/* The sketch with the object has z-index of 1 (foreground!)*/
#foregroundSketch {
z-index: 1;
position: absolute;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>

Disable redrawing canvas after screen resize and mobile rotation in PaperJS

The use case is for a Christmas "scratch" card, where the user needs to swipe on the image to reveal the content. When the window is resized or the phone is rotated, the canvas is redrawn. My current code is as follows:
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Division Raster</title>
<script type="text/javascript" src="wp-content/themes/generatepress_child/paper-full.min.js"></script>
<script type="text/paperscript" canvas="canvas">
// Based on 'JPEG Raster' by Jonathan Puckey:
// http://www.flickr.com/photos/puckey/3179779686/in/photostream/
// Create a raster item using the image with id='mona'
var raster = new Raster('mona');
// Make the raster invisible:
raster.visible = true;
raster.position = view.center;
var lastPos = view.center;
function moveHandler(event) {
if (lastPos.getDistance(event.point) < 1)
return;
lastPos = event.point;
var size = this.bounds.size.clone();
var isLandscape = size.width > size.height;
// If the path is in landscape orientation, we're going to
// split the path horizontally, otherwise vertically:
size /= isLandscape ? [2, 1] : [1, 2];
if (size.ceil().width > 10) {
var path = new Path.Rectangle({
point: this.bounds.topLeft.floor(),
size: size.ceil(),
onMouseMove: moveHandler
});
path.fillColor = raster.getAverageColor(path);
var path = new Path.Rectangle({
point: isLandscape
? this.bounds.topCenter.ceil()
: this.bounds.leftCenter.ceil(),
size: size.floor(),
onMouseMove: moveHandler
});
path.fillColor = raster.getAverageColor(path);
}
this.remove();
}
function onResize(event) {
project.activeLayer.removeChildren();
// Transform the raster so that it fills the bounding rectangle
// of the view:
raster.fitBounds(view.bounds, true);
// Create a path that fills the view, and fill it with
// the average color of the raster:
new Path.Rectangle({
rectangle: view.bounds,
fillColor: raster.getAverageColor(view.bounds),
onMouseMove: moveHandler
});
}
</script>
<style type="text/css" id="wp-custom-css">
#canvas{
background: center center url(/web.jpg);
width:100%;
height:100vh;
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
margin: 0 auto;
}
#cc{
max-width:2560px;
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
margin: 0 auto;
} </style>
</head>
<body>
<canvas id="canvas" resize></canvas>
<img width="1024" height="1024" id="mona" style="display: none;" src="/web.jpg">
</body>
</html>
Is there any way to fix the initial canvas size so the result of the "scratching" isn't lost?
Your problem resides in the onResize function which is called every time the window is resized and which basically reset your drawing.
The resize attribute on the <canvas> element also is part of the problem as it makes sure that the canvas size is updated every time the window is resized.
In your case, I think that you want to get rid of those.
Here is a fiddle adapted from your code, turning it into a static drawing that doesn't respond to resize events.
<html>
<head>
<meta charset="UTF-8">
<title>Division Raster</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.2/paper-full.min.js"></script>
<script type="text/paperscript" canvas="canvas">
// Load image then init.
var raster = new Raster({
source: 'http://assets.paperjs.org/images/marilyn.jpg',
crossOrigin: 'anonymous',
onLoad: init
});
function init() {
// Make image fill the whole canvas.
raster.fitBounds(view.bounds, true);
var lastPos = view.center;
function moveHandler(event) {
if (lastPos.getDistance(event.point) < 1) {
return;
}
lastPos = event.point;
var size = this.bounds.size.clone();
var isLandscape = size.width > size.height;
// If the path is in landscape orientation, we're going to
// split the path horizontally, otherwise vertically:
size /= isLandscape ? [2, 1] : [1, 2];
if (size.ceil().width > 10) {
var path = new Path.Rectangle({
point: this.bounds.topLeft.floor(),
size: size.ceil(),
onMouseMove: moveHandler
});
path.fillColor = raster.getAverageColor(path);
var path = new Path.Rectangle({
point: isLandscape
? this.bounds.topCenter.ceil()
: this.bounds.leftCenter.ceil(),
size: size.floor(),
onMouseMove: moveHandler
});
path.fillColor = raster.getAverageColor(path);
}
this.remove();
}
// Create a path that fills the view, and fill it with
// the average color of the raster:
new Path.Rectangle({
rectangle: view.bounds,
fillColor: raster.getAverageColor(view.bounds),
onMouseMove: moveHandler
});
}
</script>
<style type="text/css">
canvas {
width : 100vw;
height : 100vh;
position : absolute;
top : 0;
left : 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>

How do I detect when a node with a custom renderer is clicked or hovered over in sigma.js?

I am using sigma.js and have a custom node renderer that draws a node as a rectangle. Inside the rectangles are more shapes (basically just more rectangles and some text). I am also using the dragNodes plugin.
Right now, when a user wants to click on a node or drag it around the canvas, the user must go to the top left coordinate. However, the rectangle (the outermost one encompassing all the shapes inside it) represents the whole node. How do I modify my code to specify the dimensions of a node?
Also, although not shown in the code, if a user clicks inside a node rectangle (on one of the inner rectangles), I also want that to be detected and have a callback. Is this possible?
An example demonstrating my problem is shown here:
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#*" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/1.1.0/sigma.min.js"></script>
<script src="http://rawgit.com/jacomyal/sigma.js/master/plugins/sigma.plugins.dragNodes/sigma.plugins.dragNodes.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script>
$(document).ready(function() {
console.log('ready');
var g = { nodes: [], edges: [] };
g.nodes.push({
id: 'n1',
label: 'node1',
type: 'rtype',
x: Math.random(),
y: Math.random(),
size: 1,
color: '#666'
});
g.nodes.push({
id: 'n2',
label: 'node2',
type: 'rtype',
x: Math.random(),
y: Math.random(),
size: 1,
color: '#666'
});
sigma.renderers.def = sigma.renderers.canvas;
sigma.canvas.labels.rtype = function(node, context, settings) { };
sigma.canvas.nodes.rtype = function(node, context, settings) {
var prefix = settings('prefix') || '';
var size = node[prefix + 'size'];
var x = node[prefix + 'x'],
y = node[prefix + 'y'];
context.strokeStyle = 'rgb(0,0,0)';
context.strokeRect(x, y, 200, 200);
};
sigma.canvas.drawLabels = true;
var s = new sigma({
graph: g,
container: 'graph-container'
});
var dragListener = sigma.plugins.dragNodes(s, s.renderers[0]);
});
</script>
</head>
<body>
<div id="container">
<style>
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
}
</style>
<div id="graph-container"></div>
</div>
</body>
</html>

Adding objects into an array in javascript

I am trying to get the mouse pointer coordinates and store them into an array(tail) such that the array is limited only to 100 objects. If extra objects comes,the old one's are to be replaced with the new one's. Basically like a queue.
Basically i am trying to create a trail after the basic circle using a circle of smaller radius.
Here's my js:
$(document).ready(function() {
var tail = {
x:0,
y:0
};
var i = 0;
var stage = new Kinetic.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
listening: true
});
var layer = new Kinetic.Layer({
listening: true
});
var layer = new Kinetic.Layer();
var player = new Kinetic.Circle({
x: 20,
y: 20,
radius: 6,
fill: 'cyan',
stroke: 'black',
draggable: true
});
var pixel = new Kinetic.Circle({
x: 20,
y: 20,
radius: 2,
width: stage.getWidth(),
height: stage.getHeight(),
fill: "white"
});
layer.add(player);
stage.add(layer);
// move the circle with the mouse
stage.getContent().addEventListener('mousemove', function() {
player.setPosition(stage.getPointerPosition());
console.log(stage.getPointerPosition());
var obj = {
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y
}
tail[i].push(obj);
++i;
console.log(tail[i]);
// pixel.setPosition(tail[i], tail[i + 1]);
layer.draw();
});
});
And here's the html:
<!DOCTYPE html>
<html>
<head>
<title>Collision Detection</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="../css/style.css"/>
</head>
<body>
<div id="container" style=" background:#000; margin:auto; float:left;"></div>
<script src="../js/jquery.min.js"></script>
<script src="../js/kinetic-v5.0.0.min.js"></script>
<script src="../js/main_kinetic.js"></script>
</body>
</html>
Output:
Uncaught TypeError: Cannot call method 'push' of undefined main_kinetic.js:46
Object {x: 656, y: 175} --> console output which returns the cursor position.
Here's the fiddle: http://jsfiddle.net/BVeTH/
You could create your own container for your data points that handles only keeping 100 (or however many you want). Something like this:
var LimitedArray = function (upperLimit) {
var storage = [];
// default limit on length if none/invalid supplied;
upperLimit = +upperLimit > 0 ? upperLimit : 100;
this.push = function (item) {
storage.push(item);
if (storage.length > upperLimit) {
storage.shift();
}
return storage.length;
};
this.get = function (i) {
return storage[i];
};
this.iterateItems = function (iterator) {
var i, l = storage.length;
if (typeof iterator !== 'function') { return; }
for (i = 0; i < l; i++) {
iterator(storage[i]);
}
};
};
(see here: http://jsfiddle.net/Frm27/4/)
Then you can track your datapoints easily:
var trail = new LimitedArray(100);
// code...
// move the circle with the mouse
stage.getContent().addEventListener('mousemove', function() {
player.setPosition(stage.getPointerPosition());
console.log(stage.getPointerPosition());
var obj = {
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y
}
trail.push(obj);
trail.iterateItems(function (item) {
// Do something with each item.x and item.y
});
// pixel.setPosition(tail[i], tail[i + 1]);
layer.draw();
});
Unless you reassign it somewhere I am not seeing tail is not an array.
var tail = {
x:null,
y:0
};
If you wanted to store objects with x and y coordinates in it you would need
var tail = [{
x:null,
y:0
}];
tail.push(...);

Drag and drop using Raphael.js has laggy performance with more than 10 draggable elements

I'm making a simple HTML5 app, that will be wrapped to be used on Android, iOS and web browsers. In my app I need a set of points to be dragged and sorted in a certain way, I'm using raphael.js for the animations and movememts and it works fine with 3 or 4 circles, but when I use more the laggy performance appears (mobile browser). I also need the app to be able to draw lines on freehand, like a marker, and the code i'm using refers to drag to, so the performance is awful. The interesting part is that the first moves work great, as i move more elements the performance drops down drastically. It works fine in the pc browser, but works fine for 3 or 4 movements on the mobie browser.
Is there any way to make drag and drop run fast and smooth with large quantity of elements?
Here's the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Raphaël · Drag-n-drop</title>
<link rel="stylesheet" href="demo.css" type="text/css" media="screen">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon-precomposed" href="/Raphael.png">
<link rel="stylesheet" href="demo-print.css" type="text/css" media="print">
<style>
#background {
width: 100%;
height: 100%;
position: fixed;
left: 0px;
top: 0px;
z-index: -1; /* Ensure div tag stays behind content; -999 might work, too. */
}
.stretch {
width:100%;
height:100%;
}
</style>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="raphael-min.js"></script>
<script>
window.onload = function () {
var y = $(window).height();
var x = $(window).width();
y=y/30;
var posX=y;
var posY=y;
var posX2=x-y;
var R = Raphael(0, 0, "100%", "100%");
var nJ=10
var jugador=new Array();
var rival=new Array();
crearJugadores(nJ);
crearRivales(nJ);
function crearJugadores(nJ) {
nJ=nJ;
for (var i=0;i<nJ;i++)
{
jugador[i]= R.circle(posX, posY, y).attr({fill: "hsb(0, 1, 1)", stroke: "none", opacity: .5});
posY=posY+(2*y);
};
};
function crearRivales(nJ) {
posX=x-y;
posY=y;
nJ=nJ;
for (var i=0;i<nJ;i++)
{
rival[i]= R.circle(posX, posY, y).attr({fill: "#214dcf", stroke: "none", opacity: .5});
posY=posY+(2*y);
};
};
var start = function () {
this.ox = this.attr("cx");
this.oy = this.attr("cy");
this.animate({r: (1.5*y), opacity: .3}, 100, ">");
},
move = function (dx, dy) {
this.attr({cx: this.ox + dx, cy: this.oy + dy});
},
up = function () {
this.animate({r: y, opacity: 1}, 500, ">");
};
R.set(rival).drag(move, start, up);
R.set(jugador).drag(move, start, up);
initDrawing(R);
};
var g_masterPathArray;
var g_masterDrawingBox;
var g_masterPaper;
function initDrawing(R) {
g_masterPaper = R;
var masterBackground = g_masterPaper.rect(0,0,"100%","100%");
masterBackground.attr({fill:"blue", opacity: 0});
masterBackground.mousemove(function (event) {
var evt = event;
var IE = document.all?true:false;
var x, y;
if (IE) {
x = evt.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = evt.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
else {
x = evt.pageX;
y = evt.pageY;
}
// subtract paper coords on page
this.ox = x;
this.oy = y;
});
var start = function () {
g_masterPathArray = new Array();
},
move = function (dx, dy) {
if (g_masterPathArray.length == 0) {
g_masterPathArray[0] = ["M",this.ox,this.oy];
g_masterDrawingBox = g_masterPaper.path(g_masterPathArray);
g_masterDrawingBox.attr({stroke: "#000000","stroke-width": 3});
}
else
g_masterPathArray[g_masterPathArray.length] =
["L",this.ox,this.oy];
g_masterDrawingBox.attr({path: g_masterPathArray});
},
up = function () {
;
};
masterBackground.drag(move, start, up);
masterBackground.toBack();
}
</script>
</head>
<body>
<div id="background">
<img src="cancha.jpg" class="stretch" alt="" />
</div>
<div id="holder"></div>
</body>
</html>
Any ideas??
Thanks

Categories