Way to reference objects in Raphael JS? - javascript

I am trying to draw shapes based off of where on the screen existing shapes are, so that I only have to change the coordinates of one shape for all the others to shift appropriately. Is there some way to reference a rectangle's x coordinate when constructing another?
For example, the following code does not work as I thought it would:
var paper = Raphael(0, 0, 1000,600);
var rectangleOne = paper.rect(100, 100, 100, 50);
var rectangleTwo = paper.rect(rectangleOne.x, rectangleOne.y + 40, rectangleOne.width + 50, rectangleOne.height);
I get some error that "rectangleOne.x" is undefined and defaults to zero...Any ideas how to fix this? Thanks all!

var rectangleTwo = paper.rect(rectangleOne.attr('x'), rectangleOne.attr('y') + 40, rectangleOne.attr('width') + 50, rectangleOne.attr('height'));

Related

Width of dynamic rectangle in spark ar is not showing correctly

I've created a dynamic rectangle with a width and height of 100, and then changed its x position to 10. Spark AR shows its position as 10, but not the width/height, which appear as 0,03748
Here's a screenshot of how it looks like
const [dynamicRectangle] = await Promise.all([
Scene.create("PlanarImage", {
"name": "Rectangle",
"width": 100,
"height": 100,
"hidden": false,
"material": material,
}),
]);
const dynamicRectangleTransform = dynamicRectangle.transform;
dynamicRectangleTransform.x = 10;
Why? I figured it might have something to do with the canvas width, because multiplying it by the rectangle width, returns the correct number, HOWEVER it seems to have broken the code somehow, because when I add these lines of code, this happens.
const newWidth = dynamicRectangle.width.mul(canvas.bounds.width);
dynamicRectangle.width = newWidth;
const newHeight = dynamicRectangle.height.mul(canvas.bounds.height);
dynamicRectangle.height = newHeight;
In case you didn't notice from the screenshot, it now properly appears as 100, but now the rectangle doesn't appear in the canvas even though it should be visible, and position is back to 0, when it should clearly be 10. It isn't visible in my example, but it also makes so every line of Diagnostics.watch() stop working.
What am I doing wrong? I've tried hundreds of things and this keeps happening.
Try this,
Convert your rectangle to a Block
Using script, pass the new width and height to the block.
Ex : block.inputs.setScalar("widthValue", 123);
Within the Block, receive the value and update the rectangle using patches.

Raphaël JS paper.getById() returns null

I'm trying to get the Raphaël object by using the getById() function, however no matter what I try the function returns null.
Here is the Raphaël JS code I'm working with:
// Creates canvas 320 × 200 at 10, 50
var paper = Raphael(10, 50, 320, 200);
var circle = paper.circle(100, 100, 100);
circle.attr({"fill": "#f00", "id": "test"});
circle.data("id", "test");
var getCircle = paper.getById("test");
alert(getCircle); //Returns null?
Why doesn't paper.getById("test"); return the circle object?
I've defined the ID by both using attr() and data() yet nothing seems to work.
JsFiddle of the above code: http://jsfiddle.net/Mf9q6/
Read the documentation carefully:
Returns you element by its internal ID.
This is not the same as the id attribute on the element. The id expected by Paper.getById() is Element.id
You probably want var getCircle = paper.getById(circle.id); which is just a reference to the same object as circle anyway.
Here's your fiddle, updated.
If I understood your question correctly, you are trying to set id to your element. Then somewhere down the line get the element's id.
If it is the case then you are almost there:
// Creates canvas 320 × 200 at 10, 50
var paper = Raphael(10, 50, 320, 200);
var circle = paper.circle(100, 100, 100);
circle.attr({"fill": "#f00", "id": "test"});
circle.data("id", "test");
var getCircle = circle.data("id");
alert(getCircle); //Returns test
EDIT
If you are trying to get the circle by the value, like in your example "test"
paper.forEach(function (el)
{
if (el.data("id") == "test")
// return el - do what you want
});

getBounds() returns the same as getTransformedBounds() on a Shape() which has been scaled

I'm having an issue with obj.getTransformedBounds() of a Shape().
The getBounds() method should return a rectangle (if it was set using setBounds()) which stores the x/y/w/h of the Shape() within its OWN coordinate space - it's real width & height with no transformations applied.
The getTransformedBounds() method should return a rectangle (again, if set by using setBounds()) which stores the x/y/w/y within its PARENT'S coordinate space - the shape's width & height with transformations applied.
Instead, I see getBounds() returning only the transformed bounds of a shape that has its scaleX and/or scaleY applied:
http://jsfiddle.net/W9Tb8/1/
var shape = new createjs.Shape();
shape.graphics = new createjs.Graphics().beginFill("#f00").drawRect(0,0,100,100);
shape.setBounds(0,0,100,100);
shape.scaleX = shape.scaleY = 0.5;
console.log(shape.getBounds(), shape.getTransformedBounds()); // returns [0, 0, 50, 50], [0, 0, 50, 50]
// shape.getBounds() should return [0, 0, 100, 100]
// shape.getTransformedBounds() should return [0, 0, 50, 50}
Am I missing something?
It looks like what's happen is EaselJS is reusing some rectangle instances to help reduce memory impact. Have a look at the documentation here for more about it:
http://createjs.com/Docs/EaselJS/classes/Shape.html#method_getBounds
If you want to force it to give you the originally set bounds you'll either need to clone or copy them. I've altered your example to show how to output the original bounds using cloning.
http://jsfiddle.net/W9Tb8/2/
console.log(shape.getBounds().clone(), shape.getTransformedBounds());

Dynamically calling Canvas Functions

Is there any way to call canvas functions using apply() or a similar method, as to dynamically call canvas methods or to be able to pass an array of arguments?
Im looking for this effect
context.fillRect.apply(this,args);
If I understand you correctly:
var op = "fillRect";
var args = [
10, 10, 180, 180
];
ctx[op].apply(ctx, args);
Example: http://jsfiddle.net/eZwYQ/
your apply method should work just fine :
function rectangle(){
ctx.fillRect.apply(ctx,arguments);
}
And of course this can get more "dynamic" :
function doSomethingWithCanvas(context,action,arg1,arg2/*,...argn*/){
context[action].apply(context,Array.prototype.slice.call(arguments,2));
}
And you could use the same function to fill a rectangle, to draw a circle or to draw a simple line :
// simple line
doSomethingWithCanvas(ctx,'lineTo',10, 100);
// circle
doSomethingWithCanvas(ctx,'arc',275, 275, 200, 0, Math.PI*2, true);
// fillRect
doSomethingWithCanvas(ctx,'fillRect,10, 10, 180, 180);
PS : by providing the canvas context as an argument, you can use this function to draw on any canvas.

CoffeeScript Refactoring shared variable

I'm new to CoffeeScript and trying to understand how to refactor this example. Since both functions share canvas and context is there a way to pull them out side the functions and share them instead of repeating myself? I'm sure it is something obvious I'm missing, but I have not been able to get it to work.
CoffeeScript File
#draw_rectangle = ->
canvas = document.getElementById("main_canvas")
context = canvas.getContext("2d")
context.fillRect(50, 25, 150, 100)
#draw_square = ->
canvas = document.getElementById("main_canvas")
context = canvas.getContext("2d")
context.fillRect(100, 50, 100, 50)
HTML Body:
<body>
<canvas id="main_canvas"></canvas>
<p><a onclick="draw_square()" href="#">Draw Square</a></p>
<p><a onclick="draw_rectangle()" href="#">Draw Rectangle</a></p>
</body>
Probably the most elegant way would be to use a class, or at least an object, that would hold both methods and the canvas and context variables. The object would also keep track of whether it's been initialized already. Here's a first attempt:
painter =
draw_rectangle: ->
#init() unless #initialized
#context.fillRect 50, 25, 150, 100
draw_square: ->
#init() unless #initialized
#context.fillRect 100, 50, 100, 50
init: ->
canvas = document.getElementById "main_canvas"
#context = canvas.getContext "2d"
#initialized = true
Now, if you later decided that you wanted to have multiple canvases, it'd be very easy to change painter = to class Painter and reuse the code.
You can use a custom helper method to draw a rectangle.
canvasRectangle = (id, x, y, w, h) ->
canvas = document.getElementById(id)
context = canvas.getContext("2d")
context.fillRect(x, y, w, h)
#draw_rectangle = ->
canvasRectangle("main_canvas", 50, 25, 150, 100)
#draw_square = ->
canvasRectangle("main_canvas", 100, 50, 100, 50)

Categories