Generic: Naming structure and drawing KineticJS - javascript

This one takes a bit more to describe, sorry for the shorter title.
I currently do not have my code in front of me but might update this with the full details of how it works and where the problem is located.
Basically I notice that without doing a more or less global name (window.whatever) for the shapes/groups it will never draw them. I have done logs of the objects to see if they are proper and have seen nothing wrong with them.
The full scope is a layer first, that is passed to a function that i then create shapes and groups in a logical way, without passing the groups back and instead sending the layer as a parameter to add it from within the function. When I do it this way it seems that I can never get it to draw to the container (stage).
To add to it, I am looping to create the shapes, as I am making them variable and more percentage based then exact pixels, so I am holding the objects in an array that is generated through the loop.
I have done this flat first and it worked, however after moving it to the function it stopped working, is there any reason for this I may be missing?
Another note if it is relevant, I am using Adobe AIR.
If anyone has any ideas let me know, I will post the actual code when I can (few hours from this posting).
UPDATE:
Basically the issue I am having is that when i separate the shapes/groups into their own function it does not want to draw them at all. I have tried to call the draw function inline and also just add them to the stage later, both to my understanding will trigger the draw.
here is the code
var forms = {
selector:function(params,bind){
//globals
var parent,obj,lastWidth=0,items=[];
//setup defaults
var params = params || {};
params.x = params.x || 0;
params.y = params.y || 0;
params.active = params.active || 0;
params.height = params.height || 200;
params.children = params.children || [{
fill:'yellow'
}];
params.width = params.width || bind.getWidth();
params.margins = params.margins || 5;
//container for selector
parent = new Kinetic.Group({
x:params.x,
y:params.y,
height:params.height,
width:params.width
});
air.Introspector.Console.log(params);
var totalMargins = params.margins*(params.children.length+1),
activeWidth = (params.width-totalMargins)/2,
subItems = params.children.length-1,
subWidth = activeWidth/subItems,
itemHeight = (params.height-params.margins)/2;
//loop all children
for(var i=0;i<params.children.length;i++){
//use an array to store objects
items[i]={};
//create default object for rectangle
obj = {};
obj.y = params.margins;
obj.fill = params.children[i].fill;
if(params.active==i){
obj.width = activeWidth;
}else{
obj.width = subWidth;
}
obj.x = params.margins+lastWidth;
obj.height = itemHeight;
lastWidth = lastWidth+(params.margins+obj.width);
//create group for text
items[i].text = new Kinetic.Group({
x:0,
y:itemHeight+params.margins
});
//create box for text
items[i].box = new Kinetic.Rect({
x: params.margins,
y: params.margins,
width:params.width-(params.margins*2),
height:(params.height-itemHeight)-(params.margins*2),
fill:'yellow'
});
air.Introspector.Console.log(items[i].box);
//add box to text groups
items[i].text.add(items[i].box);
//create item
items[i].item = new Kinetic.Rect(obj);
//add groups to parent
parent
.add(items[i].item)
.add(items[i].text);
}
//add parent to the bound container
bind.add(parent);
}
}

From your question, I'm assuming bind is your Kinetic.Layer.
Make sure bind has been added to the stage: stage.add(bind);
After adding your groups/rects to bind, also do bind.draw();

I have since figured it out.
The issue is that the layer must be added to the stage before anything else is added it it. It was not in my code because I did not see it as an issue as it worked elsewhere.
Basically if you add anything to a layer, then add the layer to the stage it will fail. it must go like this:
CREATE STAGE
CREATE LAYER
ADD LAYER TO STAGE
ADD GROUPS TO LAYER
DRAW IF NEEDED
The way it was done originally is like so:
CREATE STAGE
CREATE LAYER
ADD GROUPS TO LAYER
ADD LAYER TO STAGE
DRAW IF NEEDED
The question will be updated to make this apparent, this is something that is not in the documentation as a problem (as far as I have seen) and I can see it as confusing some.

Related

Programatically create skeleton in Three.js

I am loading a model of a mechanism (e.g. a robot arm) in Three.js. Sadly the models I am using don't have a skeleton, but I have the locations, axes and so on of the joints. In order to use e.g. inverse kinematic solvers like Three-IK, I want to create a skeleton from these parameters. Since I want to use many different models I would prefer to not create the skeletons by hand but in code.
I have been trying for over a week now to create a valid bone structure from these values that reflects the model, but nothing succeeded. For example, if I create a chain of bones using the positions of the joints I get a very long skeleton which in no way matches the positions I used.
let boneParent;
let bonepos = [];
let bones = [];
model.traverse(child => {
switch(child.type) {
case "joint":
let p = new Vector3();
child.getWorldPosition(p);
bonepos.push(p);
let bone = new Bone();
boneParent && boneParent.add(p);
bone.worldToLocal(p.clone());
bone.position.copy(p);
bone.rotation.copy(child.rotation);
bone.scale.copy(child.scale);
boneParent = bone;
bones.push(bone);
break;
}
});
showPoints(scene, bonepos, 0xff0000);
const skeletonHelper = new SkeletonHelper(bones[0]);
skeletonHelper.visible = true;
scene.add(skeletonHelper);
The code above results in the screenshot below. The red markers are the positions I get from the robot joints, the line snaking into the distance is the skeleton as visualized by the SkeletonHelper.
So my question is this: it seems like I don't understand well enough how bones are handled in Three.js. How can I create a skeleton that reflects my existing model from its joint locations and orientations?
Thanks in advance!
child.getWorldPosition(p);
I'm afraid it's incorrect to apply the position in world space to Bone.position which represents the position in local space.
boneParent = bone;
This line looks problematic, too. A bone can have multiple child elements. It seems to me that this use case is not considered of your code.
After some fiddling around I found a solution:
let root = new Bone();
let parent = root;
let pos = new Vector3();
for (let joint of robot.arm.movable) {
let link = robot.getLinkForJoint(joint);
link.getWorldPosition(pos);
let bone = new Bone();
parent.add(bone);
parent.lookAt(pos);
parent.updateMatrixWorld(); // crucial for worldToLocal!
bone.position.copy(bone.worldToLocal(pos));
parent = bone;
}
The important part is to call updateMatrixWOrld() after lookAt() so that bone.worldToLocal() works correctly. Also lookAt() saves a lot of matrix hassles :)

PaperJS SymbolItems lose properties after hit result search

I'm creating a SymbolDefinition for a circle, and placing it on the canvas using new SymbolItem(definition). The circle object used to create the definition had a default position of (0,0), a default color, and no additional information because whatever defaults paper sets.
When I instance the symbol and place it at a certain position (lets say (20,30) for example), I also append some other information such as a name, some supplementary info in its data property, etc.
If I click on the placed circle, and have a callback search for that item using project#hitResultAll, the item contained within the hit result no longer possesses any of the information mentioned above. In fact, it appears to be the original circle object used to create the definition; its position is in fact (0,0), it has no name, and the data property is empty.
Here is a jsFiddle with an example (open dev console to see output).
In case the link doesn't work, here is the example code:
var canvas = paper.createCanvas(100, 100);
document.getElementById("canvasDiv").appendChild(canvas);
paper.setup(canvas);
var circle = paper.Path.Circle([0,0], 10);
circle.fillColor = 'red';
var definition = new paper.SymbolDefinition(circle);
var tool = new paper.Tool();
tool.onMouseUp = function(event){
var hitResult = paper.project.hitTestAll(event.point);
if(hitResult.length > 0){
var result = hitResult[0];
var item = result.item;
console.log("Item name should be 'Bob', but is actually " + item.name);
// Output is: Item name should be 'Bob', but is actually null
}
};
var actualCircle = new paper.SymbolItem(definition);
actualCircle.position = [20,30];
actualCircle.name = 'Bob';
console.log("Symbol Item was created with the name " + actualCircle.name);
// Output is: Symbol Item was created with the name Bob
Does anyone know why this is happening, and how I can go about solving it?
This turned out to be a bug in the paperJS hit test code. Thanks to Lehni, this has been resolved. At the time of this post, a new release has not been deployed yet, but so long as you use any version above 0.10.2, you should be safe.
If you are stuck with an older version, according to Lehni:
If you use hitTest() instead of hitTestAll(), it returns the expected result.

Change color of shape without recreating

I have a project using easelJS in that I'm trying to simply change the color of a shape object. I have a couple of examples but they both seem to indicate I would need to completely redraw the shape with a graphics.beginFill() call again. This seems completely overkill considering that I've stored my shape object already and am able to perform other manipulations on it.
I've also tried to use ColorFilter and ColorMatrix but have not had luck making a clean color change. In some cases the color essentially "overwrites" the detail of the shape.
I have an array of ShapeObject that I store the createjs.Shape() object in.
var ShapeObject = function()
{
this.name;
this.shape;
this.rotation;
this.color;
};
sObject = new ShapeObject();
myShape = new createjs.Shape();
sObject.shape = myShape;
shapes = new Array();
shapes.push(sObject);
Later I am able to retrieve the shape from the array and apply a filter, for example,
s = shapes[i];
filter = new createjs.ColorFilter(0,0,0,1, 255,128,0,0);
s.shape.filters = [ filter ];
Using this same example I'd like to avoid having to completely recreate the shape. I have tried the following but, while it changes color, I lose all the other details of the shape that was originally applied.
s.shape.graphics.clear().beginFill(color);
Does anyone have an idea of how to simply change the color without completely recreating the original shape?
EDIT
Following the answer regarding .command and the createjs command blog post I have created the following.
var theShape = new createjs.Shape();
var fillCommand = theShape.graphics.beginFill("yellow").command;
theShape.graphics.setStrokeStyle(1)
.beginStroke(createjs.Graphics.getRGB(0, 0, 0))
.drawCircle(0, 0, 20)
.moveTo(0,-20)
.lineTo(0,0)
.moveTo(0,0)
.lineTo(20,0);
fillCommand.style = "orange";
Despite being nearly identical to the examples I am receiving the error Uncaught TypeError: Cannot set property 'style' of undefined at the last line above.
I wouldn't use ColorFilter or ColorMatrix, it will likely be much slower. But you could use the Graphics command object, check out the docs: http://www.createjs.com/docs/easeljs/classes/Graphics.html
var fillCommand = myGraphics.beginFill("red").command;
// ... later, update the fill style/color:
fillCommand.style = "blue";

How to get the last shape of a specific type?

I need to find the last path or circle in a paper, in order to perform further calculations to draw more elements, and calling paper.bottom only gets the last element. Is there any way to get shapes of specific types, e.g. bottom.path, bottom.circle or to traverse for the n'th child?
I want to avoid using jQuery selectors, as i can't retrieve any properties from those.
An example of a paper populated with shapes:
var paper = Raphael('paper',500,500);
var c1 = paper.circle(100,100,50)
var p1 = paper.path("M10 20l70 0")
var c2 = paper.circle(200,100,50)
Checking for the bottom element will get you, well, the bottom element (along the Z axis) - which is undesired. Consider a case where the Z ordering of elements is altered - perhaps by calling Element.toBack() - that will invalidate the check altogether.
Instead you may want to aim for a more semantic approach by iterating over the elements array and retrieving the last element of a certain type (e.g. circle).
Raphaël also allows for extending the built-in set of functions, so we can attach a function to the paper element solely for that purpose. The following snippet shows an example of such a function which returns the last element of the passed type from the paper, or false if no such element was found:
Raphael.fn.last = function(type) {
var element;
this.forEach(function(el) {
if (el.type == type) {
element = el;
}
});
return element || !!element;
};
Be sure to attach this function before any instanciation of paper elements. Than it's only a matter of calling it, passing the desired element type:
var r = Raphael(paper, '100%', '100%');
// ...
// add elements etcetera
// ...
var lastCircle = r.last('circle');
Note that for the suggested implementation this can result in heavy operations - if the paper contains many elements, but the purpose here is to grant you with the notion of functionality extension, and kick-start the thinking process. Feel free to improve the function to increase its efficiency.
Live Demo
Regarding how to traverse for the nth child: Just put your paths in a set and they're indexed like any ordinary array. You can easily call out any number from that set, and get full access to its properties:
var myPaper = Raphael('container', '800', '600');
myPaper.setStart();
var circ1 = myPaper.circle(50, 50, 40);
var circ2 = myPaper.circle(150, 50, 40);
var circ3 = myPaper.circle(250, 50, 40);
var circ4 = myPaper.circle(350, 50, 40);
var allCircles = myPaper.setFinish();
allCircles[2].attr({fill: "blue"});
​
http://jsfiddle.net/eE7xS/

box2D (javascript)

I am just getting started with box2d. I am able to create some objects and create a world in which to use those objects. For example, to create a box (taken from: http://box2d-js.sourceforge.net/index2.html) I can do so like this:
elements = getElementsByClass("box2d");
for ( var i = 0; i < elements.length; i ++ ) {
properties[i] = getElementProperties( elements[i] );
bodyDef.type = b2Body.b2_dynamicBody;
var data = { element: elements[i]};
bodyDef.userData = data;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(2 //half width , 2);
bodyDef.position.x = Math.random() * 10;
bodyDef.position.y = Math.random() * 10;
world.CreateBody(bodyDef).CreateFixture(fixDef);
}
What I would like to do is take divs with text and turn those divs with text into shapes and use them in box2D. I really don't know where to start with this. I am using the userData property now thinking that this is at least a start.
I found a great example of this in action here: http://mrdoob.com/projects/chromeexperiments/google_gravity/
getElementProperties and getElementsByClass are defined. I was thinking about using getElementProperties to set the shape dimensions.
I am doing something similar with iOS, but a good way to approach it is to make images out of the information held in the div. Then you can make a sprite out of that image and add it as the userData for your box2d body. When you update (tick: method in iOS, I am not sure for javascript) then you iterate over all the bodies and adjust the sprite location. The box2d world should do everything else for you.
You can take reference this samples..
http://jsbin.com/efequk/5
http://www.jeremyhubble.com/box2d.html

Categories

Resources