Related
I am trying to convert a sketch to use node and bundle a distribution js file. My guess is that some of the function names in p5js must be reserved (to combat this I was going to use a development flag so as not to obfuscate the code at least for testing).
In order to encapsulate the code I am using this method:
let sketch = function(p) {
p.setup = function() {
...
}
let myp5 = new p5(sketch);
Everything seems to work fine except I cannot call the show function from inside my particle Class (ReferenceError: noStroke is not defined)
Here is the full js:
let canvasBG;
let particles = [];
let audioFile;
let amplitude;
let vol;
let loaded = false;
let x = 0;
let xoff = 0;
let yoff = 0;
let sketch = function(p) {
p.setup = function() {
canvasBG = p.createCanvas(p.windowWidth, p.windowHeight);
audioFile = p.loadSound("audio/mom.mp3", p.audioLoaded);
amplitude = new p5.Amplitude();
p.rectMode(p.CENTER);
p.frameRate(30);
canvasBG.background(255);
}
p.audioLoaded = function() {
audioFile.play();
audioFile.loop();
loaded = true;
}
p.draw = function() {
let nx = p.noise(xoff) * p.windowWidth;
let ny = p.noise(yoff) * p.windowHeight;
xoff = xoff + 0.01;
yoff = yoff + 0.02;
vol = amplitude.getLevel();
let volumeGate = p.map(vol, 0, 1, p.random(5,12), p.random(80, 550));
if (loaded) {
let b = new Particle(nx, ny, volumeGate);
particles.push(b);
if (volumeGate > 75) {
canvasBG.background(p.random(255), p.random(255), p.random(255));
}
for (let particle of particles) {
particle.show();
}
if (particles.length >= 10) {
particles.splice(0, 1);
}
} else {
x+= 0.05;
p.translate (p.windowWidth - 30, 30);
p.rotate(x);
p.noStroke();
p.rect(0, 0, 2, 40, 0.1);
p.fill(0, 0, 0, x * 3);
}
}
}
class Particle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
show() {
noStroke(); // this is throwing an error
fill(random(0, 255), random(0, 255), random(0, 255), random(100,255));
ellipse(this.x, this.y, this.r * 2);
}
}
let myp5 = new p5(sketch);
You can run the current full demo here: https://editor.p5js.org/lharby/sketches/wPF908tqX
I've tried converting the class to a function and passing in arguments, similarly an object and then attaching a function to the object, but can't seem to get anything to work plus I would rather keep the Class as it is.
How is the best way to go about this?
You're super close!
Because you're using p5 in instance mode, p5 functions (such as noStroke(), fill(), ellipse()) won't be available in the global scope, but through the p reference.
In your class you simply need to pass p as well, similar to how you've already used it with the rest of the code:
class Particle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
show(p) {
p.noStroke();
p.fill(p.random(0, 255), p.random(0, 255), p.random(0, 255), p.random(100,255));
p.ellipse(this.x, this.y, this.r * 2);
}
}
and in draw pass the reference to p5:
//...
for (let particle of particles) {
particle.show(p);
}
//...
I am creating this game where you move a block with your mouse and avoid obstacles that are being created from right side of the screen to the left, my cursor used to work fine, so did the obstacle creation, but when i combined them it doesn't seem to work anymore and i can't figure out why, here is the game code,
var myGamePiece;
var myObstacles = [];
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myGameArea.start();
}
var myGameArea = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 600;
this.canvas.height = 600;
this.canvas.style.cursor = "none";
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('mousemove', function(e) {
myGameArea.x = e.pageX;
myGameArea.y = e.pageY;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
}
}
function everyinterval(n) {
if ((myGameArea.frameNo / n) % 1 == 0) {
return true;
}
return false;
}
function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) ||
(mytop > otherbottom) ||
(myright < otherleft) ||
(myleft > otherright)) {
crash = false;
}
return crash;
}
}
function updateGameArea() {
var x, y;
for (i = 0; i < myObstacles.length; i += 1) {
if (myGamePiece.crashWith(myObstacles[i])) {
myGameArea.stop();
return;
myGameArea.clear();
myObstacle.x += -1;
myObstacle.update();
if (myGameArea.x && myGameArea.y) {
myGamePiece.x = myGameArea.x;
myGamePiece.y = myGameArea.y;
}
myGamePiece.update();
}
}
}
myGameArea.clear();
myGameArea.frameNo += 1;
if (myGameArea.frameNo == 1 || everyinterval(150)) {
x = myGameArea.canvas.width;
y = myGameArea.canvas.height - 200;
myObstacles.push(new component(10, 20, "green", x, y));
}
for (i = 0; i < myObstacles.length; i += 1) {
myObstacles[i].x += -1;
myObstacles[i].update();
}
startGame();
canvas {
border: 1px solid #d3d3d3;
background-color: #f1f1f1;
}
<body>
<p>move the cursor to move the blocky boii!</p>
</body>
if you guys figure out what's wrong with it and possibly add why and what am i doing wrong in the code in general (structure, position etc) i would be very grateful, feel free to hate and criticize the code, I am self learner and don't wont to get the wrong habits that will be difficult to get rid of in the future.
thank you for reply
I respect anyone who is open to improving, so please let me know if this helps. For further code improvements, tips, etc, I'd like to point you towards Code Review Stack Exchange. I'll put my notes and working code here, but it's bound to get rather long. First, though, your immediate errors are fixed and commented in the snippet below. (Mostly comes down to "fix your curly braces")
Errors Fixed
var myGamePiece;
var myObstacles = [];
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myGameArea.start();
}
var myGameArea = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 600;
this.canvas.height = 600;
this.canvas.style.cursor = "none";
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('mousemove', function(e) {
myGameArea.x = e.pageX;
myGameArea.y = e.pageY;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function() {
clearInterval(this.interval);
}
}
function everyinterval(n) {
if ((myGameArea.frameNo / n) % 1 == 0) {
return true;
}
return false;
}
function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) ||
(mytop > otherbottom) ||
(myright < otherleft) ||
(myleft > otherright)) {
crash = false;
}
return crash;
}
}
function updateGameArea() {
var x, y;
for (i = 0; i < myObstacles.length; i += 1) {
var myObstacle = myObstacles[i] // problem 3: this was missing
if (myGamePiece.crashWith(myObstacle)) {
myGameArea.stop();
return;
} // problem 4: needed to be closed
myGameArea.clear();
myObstacle.x += -1;
myObstacle.update();
if (myGameArea.x && myGameArea.y) {
myGamePiece.x = myGameArea.x;
myGamePiece.y = myGameArea.y;
}
myGamePiece.update();
}
// problem 1, from here down needed moved into the updateGameArea() function
// problem 2: myGameArea.clear(); needed removed from here
myGameArea.frameNo += 1;
if (myGameArea.frameNo == 1 || everyinterval(150)) {
x = myGameArea.canvas.width;
y = myGameArea.canvas.height - 200;
myObstacles.push(new component(10, 20, "green", x, y));
}
for (i = 0; i < myObstacles.length; i += 1) {
myObstacles[i].x += -1;
myObstacles[i].update();
}
}
startGame();
canvas {
border: 1px solid #d3d3d3;
background-color: #f1f1f1;
}
<p>move the cursor to move the blocky boii!</p>
Further Notes/Tips
General Development
Using some type of tool (like Atom, VSCode, etc) may help you identify where blocks start and end. You can often hover over an opening { and the matching } will get highlighted
You should delete obstacles so you don't infinitely spawn new ones
Try to keep "circular dependencies" out of your code
Time-based, rather than frame-based logic helps keep things moving smoothly. For the most basic approach, you can animate/move entities using the time since the last frame.
JavaScript
Knowing how prototypes work in JS can help keep your memory usage down and your game running faster. Your code currently adds new functions to every "component" instance when they get created
In the JS community, we have a couple standard style guides and conventions. For example, we usually capitalize constructor functions (and classes from ES2015). Check out some of the more complete guides like Standard and/or AirBnB to know what is considered common. (helps us speak the same language)
If you don't already know it, ES2015+ provides a number of improvements (often maintenance related) over older code. For example using const and let is now often more "normal" than using var, as is using arrow functions instead of regular functions. (these decisions are mostly highlighted in the style guides I provided above)
Try to avoid polluting the global namespace by creating variables like myGamePiece and myObstacles. Contain them using scoping somehow. In the code below, I used an IIFE to keep variables local to that code. The fewer implicit interactions we have between scripts, the better.
Also, avoid global functions, when you can. For example, most events you might need are best handled via .addEventListener(). Your pre-edit question included <body onload="startGame()">, which requires a global function. This can be replaced with a simple startGame() call within a script tag right above </body> OR you can use something like document.addEventListener('DOMContentLoaded', startGame)
You can create a better game loop using window.requestAnimationFrame() (see this documentation for more info)
Ideally, each of these classes and functions could be split into separate modules/files as they grow, too. It can be incredibly helpful to see the structure/architecture of an application without needing to read through the full code to understand...which leads me to the next section:
Architecture
Game developers often split up the parts of their games according to an architecture called ECS. I'd recommend learning how this works before going too deep. It's not considered a perfect architecture at its most basic form, but the goals behind it hold merit.
Also check out Functional Programming (FP) and what it considers to be "state". ECS is basically just FP within the context of a game loop.
Aligning yourself with the common terminology of each part will help you search for the details you don't yet know. I changed a few names around in my additional snippet below like "component" -> "Entity" and "crash" to "collision/collide" in an effort to align with what these parts are commonly called.
Putting the notes together...
The snippet below still isn't perfect, but I hope it demonstrates most of the points I provided above. I started with your code and slowly went through refactoring steps until it became what you see below:
;(() => {
class CanvasCamera2D {
constructor(canvas) {
this.canvas = canvas
this.context = canvas.getContext('2d')
}
get width() { return this.canvas.width }
get height() { return this.canvas.height }
clear() {
this.context.clearRect(0, 0, this.width, this.height)
}
render(fn) {
fn(this.context, this.canvas)
}
}
class Entity {
constructor(type, width, height, x = 0, y = 0) {
this.type = type
this.width = width
this.height = height
this.x = x
this.y = y
}
get left() { return this.x }
get right() { return this.x + this.width }
get top() { return this.y }
get bottom() { return this.y + this.height }
collidedWith(otherobj) {
return !(
(this.bottom < otherobj.top) ||
(this.top > otherobj.bottom) ||
(this.right < otherobj.left) ||
(this.left > otherobj.right)
)
}
}
const update = (
{ // state
gamePiece,
obstacles,
mouse,
deltaTime,
timestamp,
lastSpawnTime
},
{ // actions
stopGame,
setLastSpawnTime,
filterObstacles,
setGamePiecePosition,
},
camera
) => {
// Add an obstacle every so many milliseconds
if ((timestamp - lastSpawnTime) >= 800) {
obstacles.push(
new Entity('obstacle', 10, 20, camera.width, camera.height - 200)
)
setLastSpawnTime(timestamp)
}
// Go through each obstacle and check for collisions
filterObstacles(obstacle => {
if (obstacle.collidedWith(gamePiece)) {
stopGame()
}
// Move obstacles until they hit 0 (then remove from the list)
obstacle.x -= deltaTime / 4
return !(obstacle.x < 0)
})
// Move gamePiece with mouse
setGamePiecePosition(mouse.x, mouse.y)
}
const render = ({ gamePiece, obstacles }, camera) => {
camera.clear()
const entities = [gamePiece].concat(obstacles)
entities.forEach(entity => camera.render(ctx => {
ctx.fillStyle = entity.type === 'gamePiece' ? 'green' : 'red'
ctx.fillRect(entity.x, entity.y, entity.width, entity.height)
}))
}
const startGame = (update, render, inState, maxFrameRate) => {
const state = Object.assign({
deltaTime: 0,
timestamp: 0,
lastSpawnTime: 0,
gameRunning: true,
}, inState)
// Created in an effort to avoid direct modification of state
const actions = {
stopGame() { state.gameRunning = false },
setLastSpawnTime(time) { state.lastSpawnTime = time },
filterObstacles(fn) { state.obstacles = state.obstacles.filter(fn) },
setGamePiecePosition(x, y) { Object.assign(state.gamePiece, { x, y }) },
setMousePosition(x, y) { Object.assign(state.mouse, { x, y }) },
}
// Set up camera
const canvas = Object.assign(document.createElement('canvas'), {
width: 300,
height: 300,
})
document.body.insertBefore(canvas, document.body.childNodes[0])
const camera = new CanvasCamera2D(canvas)
// Update state when mouse moves (scaled in case canvas changes in size)
window.addEventListener('mousemove', e => {
actions.setMousePosition(
e.pageX * (canvas.width / canvas.clientWidth),
e.pageY * (canvas.height / canvas.clientHeight),
)
})
// Start game loop
let lastTimestamp = performance.now()
const loop = (timestamp) => {
const delta = timestamp - lastTimestamp
if (delta > MAX_FRAME_RATE) {
state.timestamp = timestamp
state.deltaTime = delta
update(state, actions, camera)
render(state, camera)
lastTimestamp = timestamp
if (!state.gameRunning) return
}
requestAnimationFrame(loop)
}
loop(performance.now())
}
const MAX_FRAME_RATE = 60 / 1000
startGame(update, render, {
mouse: { x: 0, y: 0 },
gamePiece: new Entity('gamePiece', 30, 30, 10, 120),
obstacles: [],
}, MAX_FRAME_RATE)
})()
canvas {
border: 1px solid #d3d3d3;
background-color: #f1f1f1;
max-width: 100%;
cursor: none;
}
<p>move the cursor to move the blocky boii!</p>
I have a card class:
function Card() {
this.image = new Image();
this.x = 0;
this.y = 400;
this.initialX = 0;
this.initialY = 0;
this.scaleFactor = 4;
this.setImage = function(ii){
this.image.src = ii;
};
this.getWidth = function(){
if (this.image == null){
return 0;
}
return this.image.width / this.scaleFactor;
}
this.getHeight = function(){
if (this.image == null){
return 0;
}
return this.image.height / this.scaleFactor;
}
this.pointIsInCard = function(mx, my){
if (mx >= this.x && mx <= (this.x + this.getWidth()) && my >= this.y && my <= (this.y + this.getHeight()))
{
return true;
}
else{
return false;
}
};
};
I then have a deck class:
function Deck(x, y, w, h){
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.cards = [];
}
I need to add a method in Deck class similar to pointIsInCard instead it will be called pointIsInDeck. The logic will be same i.e to check whether the passed in point falls in the boundary of the object. So seeing this duplication of code I wanted to know what is a good design practice to avoid this duplication? One option I thought of was to extract the method out and create a function for generic object with x, y, width, height but again from OOP principles I thought this method should belong to the class/object. I appreciate any help! Thanks!
A common approach for what you're doing is to attach a Rectangle or similar instance with that functionality to both of your objects, that is:
class Rectangle {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
containsPoint(x, y) {
return x >= this.x && x =< this.width &&
y >= this.y && y =< this.height;
}
}
Then just add it to Card and Deck:
function Card() {
this.rect = new Rectangle(/* Your card shape */);
// ...
}
function Deck() {
this.rect = new Rectangle(/* Your deck shape */);
// ...
}
And you can do:
card.rect.containsPoint();
deck.rect.containsPoint();
If these are classes related to drawing, they would both inherit from something like Rectangle, which they would both inherit this behaviour from.
If they are gameplay-related, I would prefer them each referencing a Rectangle (or its subclass) that they would delegate all UI-related tasks to; then reduce this to the previous paragraph's solution.
You can use Function.prototype.call() to set this at a function call
function Card() {
this.x = 1; this.y = 2;
};
function Deck() {
this.x = 10; this.y = 20;
}
function points(x, y) {
// do stuff
console.log(x, this.x, y, this.y); // `this`: `c` or `d`
}
var c = new Card();
var d = new Deck();
points.call(c, 3, 4); // `this`: `c` within `points` call
points.call(d, 100, 200); // `this`: `d` within `points` call
I'm creating a Game Loop in javascript using var/function classes (for want of a better word). However, I have this strange error where javascript states that a variable is undefined immediately after declaring it...
main.js:39 Uncaught ReferenceError: game is not defined
In this case, that line is;
game.context.beginPath();
However, this line is not called until the init function calls game.balls.push(/../); Haven't I already declared 'game' by this point, or am I missing something?
Here is my code (Apologies for the length, hopefully most of it can be ignored):
/*
Keep This: #217398
*/
var Game = function () {
this.canvas = document.getElementById('canvas');
this.context = this.canvas.getContext('2d');
this.balls = [];
var that = this;
this.start = function () {
requestAnimationFrame(that.update);
};
this.update = function () {
that.draw();
requestAnimationFrame(that.update);
};
this.draw = function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
for(var x = 0; x < this.balls.length; x++){
this.balls[x].draw();
}
};
this.start();
};
var Ball = function (x, y) {
this.x = x;
this.y = y;
this.dx = 2;
this.dy = 2;
this.ballRadius = 10;
this.draw = function(){
game.context.beginPath();
game.context.arc(this.x, this.y, this.ballRadius, 0, Math.PI*2);
game.context.fillStyle = 'black';
game.context.fill();
game.context.closePath();
this.x += this.dx;
this.y += this.dy;
if(this.x + this.dx > game.canvas.width - this.ballRadius || this.x + this.dx < this.ballRadius)
this.dx = -this.dx;
if(this.y + this.dy > game.canvas.height - this.ballRadius || this.y + this.dy < this.ballRadius)
this.dy = -this.dy;
};
};
function init(){
var game = new Game();
game.canvas.addEventListener('click', function(){
game.balls.push(new Ball(100, 100));
});
}
Update Ball() so that you can explicitly pass in a reference to the Game() instance:
var Ball = function (game, x, y) {
this.x = x;
this.y = y;
// etc
};
Then:
function init(){
var game = new Game();
game.canvas.addEventListener('click', function(){
game.balls.push(new Ball(game, 100, 100));
});
}
Now the Ball() code has access to a reference to the Game() instance you created.
Because you declared the game variable using the var keyword within the init function, it will be scoped to the init function (and not available to other functions not nested within init).
function init(){
var game = new Game(); // will be scoped to init
game.canvas.addEventListener('click', function(){
game.balls.push(new Ball(100, 100));
});
}
So, one option would be to declare game outside of init which would broaden it's scope, or you could declare it as an instance variable to Ball.
The variable game is scoped to the init function in which it is created. This means that it can't be accessed outside of this function. There are many work arounds for this. You could make game a global variable, or pass it to the Ball constructor.
Another possible solution is having a global namespace which keeps track of these important objects.
var SomeNamespace= {};
SomeNamespace.game= new Game();
What I personally like to do is run my simple games in closures.
(function(){
var game = new Game();
var ball = new Ball(); // Ball now has access to game.
})()
Sidenote, you can create globally scoped variables within functions, by omitting the var keyword, but it's considered a bad practice.
I would like to create a custom Raphael element, with custom properties and functions. This object must also contain predefined Raphael objects. For example, I would have a node class, that would contain a circle with text and some other elements inside it. The problem is to add this new object to a set. These demands are needed because non-Raphael objects cannot be added to sets. As a result, custom objects that can contain Raphael objects cannot be used. The code would look like this:
var Node = function (paper) {
// Coordinates & Dimensions
this.x = 0,
this.y = 0,
this.radius = 0,
this.draw = function () {
this.entireSet = paper.set();
var circle = paper.circle(this.x, this.y, this.radius);
this.circleObj = circle;
this.entireSet.push(circle);
var text = paper.text(this.x, this.y, this.text);
this.entireSet.push(text);
}
// other functions
}
var NodeList = function(paper){
this.nodes = paper.set(),
this.populateList = function(){
// in order to add a node to the set
// the object must be of type Raphael object
// otherwise the set will have no elements
this.nodes.push(// new node)
}
this.nextNode = function(){
// ...
}
this.previousNode = function(){
// ...
}
}
You can only add Raphael object (rect,circle, eclipse,text) to paper.set(), not self defined object( with Raphael.fn) . Instead use normal array definition of javascript [].
As fas as i understand nodeList is a simple list but with more options like nextnode , previous nodes.
Take a look at this demo, i changed abit José Manuel Cabrera's codes: http://jsfiddle.net/Tomen/JNPYN/1/
Raphael.fn.node = function(x, y, radius, txt) {
this.x = x;
this.y = y;
this.radius = radius;
this.txt = txt;
this.circleObj = paper.circle(this.x, this.y, radius), this.textObj = paper.text(this.x, this.y, this.txt);
this.entireSet = paper.set(this.circleObj, this.textObj);
return this
}
Raphael.fn.nodeList = function() {
this.nodes = [];
this.push = function(p) {
return this.nodes.push(p);
};
// this.nextNode = function(){
// ... manipulate this.nodes here
// }
// this.previousNode = function(){
// ...
// }
return this
}
var ca = paper.node(250, 150, 50.0, "hola");
var list = paper.nodeList();
list.push(ca);
Some examples may fall down if there is no global 'paper'
The context of Raphael.fn.yrMethod will be the instance (paper)
This example creates a raphael object which wraps a g element, which is for some reason not currently supported:
(function(R){
function g(_paper){
var _canvas = _paper.canvas,
_node = document.createElementNS("http://www.w3.org/2000/svg", "g");
_canvas.appendChild(_node);
this.add = function(rElement){
_node.appendChild(rElement.node);
}
this.remove = function(rElement){
_canvas.appendChild(rElement.node);
}
this.transform = function(tString){
_node.setAttribute('transform', tString);
}
}
R.fn.g = function(){
return new g(this);
}
})(Raphael);
this code allow you to create a node with a text (it returns a set) and you can manipulate it as a Raphael object (put the method after loading the dom):
function loadShape(){
Raphael.fn.node = function(x, y, radius, txt){
this.x = x;
this.y = y;
this.radius = radius;
this.txt = txt;
this.drawCircle = function () {
return paper.circle(this.x, this.y, radius);
};
this.drawText = function () {
return paper.text(this.x, this.y, this.txt);
};
this.draw = function(){
var group = paper.set();
var circulo = paper.circle(this.x, this.y, radius);
var texto = paper.text(this.x, this.y, this.txt);
group.push(circulo);
group.push(texto);
return group;
}
this.init = function(ox, oy, r, t){
this.x = ox;
this.y = oy;
this.radius = r;
this.txt = t;
};
// etc…
return this;
};
var paper = new Raphael(document.getElementById("wrapper"), "100%", "100%");
//var nodo = paper.node();
//nodo.init(50, 50, 2.0, "soy un nodo");
var nodo = paper.node(250, 150, 50.0, "hola");
nodo.draw();
//circ.attr({"propiedad":"hola"});
//alert(circ.attr("propiedad"));
}
Tell me if this was useful to you!