I would like to know, how can I add peoperties to some KineticJS object. For example - I create two rectangles and connect them with a Line. And I need the object "line" knows about the two rectangles.
I could create a class Connector with atributtes object1, object2 and line (Kinetic.Line). But I can add to canvas only the line, so that I would lost the reference to Connector object, if I tried to get the line from canvas - for example after clicking on that.
If I understand your question correctly, its fairly simple
var rect1 = new Kinetic.Rect({...});
var rect2 = new Kinetic.Rect({...});
var line = new Kinetic.Line({...});
line.r1 = rect1;
line.r2 = rect2;
Now you can simply access the 2 rectangles by using line.r1 and line.r2
Related
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";
I am making a document that will build a tree type graph through user input. I am trying to connect styled divs to the relative div they branched from with canvas lines.
I have been using .getBoundingClientRect() to get the positions, but the divs are static with inline-block, so every time a new one is added, the whole structure changes.
So, here is my attempt at a 'for loop' that is called every time a new branch is made, to re-draw all of the canvas lines.
var lines = function(){
var blocks=document.getElementsByClassName('block');
for (i=1;i<blocks.length-1;i++){
var blockDiv = blocks[i]
var offset = blockDiv.getBoundingClientRect();
var xa = offset.left+40;
var ya = offset.top+40;
var blockFrom = blockDiv.parentNode.parentNode.previousSibling;
var offsets = blockFrom.getBoundingClientRect();
var yb = offsets.top+40;
var xb = offsets.left+40;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.moveTo(xa,ya);
ctx.lineTo(xb,yb);
ctx.stroke();
}
}
Here is a jsfiddle so you can see the general structure of the divs.
When the function is called, I get no canvas lines and a console error of
166 Uncaught TypeError: blockDiv.parentNode.parentNode.previousSibling.getBoundingClientRect is not a function
I am stumped on this one and would really appreciate the help.
I am new to canvas, javascript, and coding in general so any other constructive criticism would also be greatly appreciated. :)
Vanilla js only please!
The problem is this:
Gecko-based browsers insert text nodes into a document to represent
whitespace in the source markup. Therefore a node obtained, for
example, using Node.firstChild or Node.previousSibling may refer to a
whitespace text node rather than the actual element the author
intended to get.
https://developer.mozilla.org/en-US/docs/Web/API/Node/previousSibling
Therefore, change this line:
var blockFrom = blockDiv.parentNode.parentNode.previousSibling;
to this:
var blockFrom = blockDiv.parentNode.parentNode.previousSibling.previousSibling;
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.
I am following Mike Bostock's pattern for reusable charts - closures with getter/setters. But somehow, when I instantiate a new chart object with new properties, existing charts are being updated with these properties:
var chart1 = new StackedAreaChart();
d3.select('#chart1')
.data([data])
.call(chart1);
// a new chart - whose properties end up in chart1!
var chart2 = new StackedAreaChart().colors(['green', 'blue']);
Here's an example: http://jsfiddle.net/samselikoff/YZ6Ea/3/. Resize the window to see the first chart re-rendered, with a stylish but unexpected green tint.
I am baffled by this. I suspect (1) my setter is mutating the actual 'constructor', and (2) somehow chart1 is really a reference to this constructor, rather than being a separate instance of it like I thought.
I was thinking of using this.margin = ... instead of var margin =, but since this is the suggested pattern I wanted to post here first. What am I missing?
If you are following Mike's tutorial, you shouldn't be using new when creating the chart:
var chart1 = StackedAreaChart();
d3.select('#chart1')
.data([data])
.call(chart1);
StackedAreaChart will return a function, and that function will be called once for each element in the selection when the data is binded.
I am trying to manually define the vertices of a polygon in box2D for javascript. I ultimately want to resize each side of a box manually, but I need to be able to draw it with vertices first (I already have a resizing mechanism). I've looked at the examples in the manual, but they are for ActionScript, and it doesn't seem to work in javascript. I've tried defining the polygon in different ways (like standalone polygon = new b2Polygon;), but it makes no difference.
No matter how I define a new polygon, the box2D source is throwing an error in the call to create the fixture. The error says "tVec is undefined," which is a variable in the box2D function: b2PolygonShape.prototype.ComputeAABB = function (aabb, xf)
Here are the relevant parts of the code(fixDef and bodyDef are created earlier in the code):
var vertices = [];
vertices[0] = new b2Vec2()
vertices[0].Set(1,1);
vertices[1] = new b2Vec2();
vertices[1].Set(1, 6);
vertices[2] = new b2Vec2();
vertices[2].Set(6, 6);
vertices[3] = new b2Vec2();
vertices[3].Set(6, 1);
fixDef.shape = new b2PolygonShape;
fixDef.shape.Set(vertices, 4);
world.CreateBody(bodyDef).CreateFixture(fixDef);
Any help would be greatly appreciated as this has been giving me trouble for a while now.