Change color of shape without recreating - javascript

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";

Related

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.

Generic: Naming structure and drawing KineticJS

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.

Three JS No Visual Update After Manually Editing Geometry

So I have a Geometry (the scope of this code is THREE.Geometry.prototype) and I am dynamically editing. newData is an object of { faces: [array of face Indexes], vertices: [array of vertice indexes]}. (these arrays maintain the length of the origin face and vertices arrays length and hold the form [null, null, null, "4", "5", null, null... ])
Using these arrays, I strip through all the faces and vertices and apply them to 1 of 2 new arrays, effectively splitting all the data into 2 groups. I also update the pointers on the faces!
In the end I know I've updated the geometry and it is correct, but the changes I make aren't getting displayed. I've tried .elementsNeedUpdate which causes and error. (no property 'a' of undefined in InitWebGlObjects... I looked there, couldn't see a reference to a)
I've tried vertices need update, it does nothing.
I've also tried updateCentroids in combination with the previous tool. It does nothing.
I've heard of not being able to resize the buffer. What is the buffer and the length of the buffer? The amount of verticies I'm giving to a model?
I've seen "You can emulate resizing by pre-allocating larger buffer and then keeping unneeded vertices collapsed / hidden." It sounds like that may be what I'm doing? How can I collapse/ hide a vertice? I haven't seen any references to that.
Thanks for your time!
var oldVertices = this.vertices
var oldFaces = this.faces;
var newVertices = []
var newFaces = [];
var verticeChanges = [];
this.vertices = [];
this.faces = [];
for(var i in oldVertices){
var curAr = ((newData.vertices[i]) ? (newVertices):(this.vertices));
curAr.push(oldVertices[i]);
verticeChanges[i] = curAr.length-1;
}
for(var i in oldFaces){
var curAr = ((newData.faces[i]) ? (newFaces):(this.faces));
oldFaces[i].a = verticeChanges[oldFaces[i].a];
oldFaces[i].b = verticeChanges[oldFaces[i].b];
oldFaces[i].c = verticeChanges[oldFaces[i].c];
}
console.log('Vertices Cut from', oldVertices.length, "to:", newVertices.length, 'and', this.vertices.length);
console.log('Faces Cut from', oldFaces.length, "to:", newFaces.length, 'and', this.faces.length);
I recently ran into this problem myself. I found that if I'm adding vertices and faces to the geometry, I need to set this.groupsNeedUpdate = true in order to tell the renderer to update it's internal buffers.
Maybe connected to this point from this tutorial:
"I just wanted to quickly point out a quick gotcha for Three.js, which
is that if you modify, for example, the vertices of a mesh, you will
notice in your render loop that nothing changes. Why? Well because
Three.js (as far as I can tell) caches the data for a mesh as
something of an optimisation. What you actually need to do is to flag
to Three.js that something has changed so it can recalculate whatever
it needs to. You do this with the following:
// set the geometry to dynamic so that it allow updates
sphere.geometry.dynamic = true;
// changes to the vertices
sphere.geometry.__dirtyVertices = true;
// changes to the normals
sphere.geometry.__dirtyNormals = true;"

Add property to KineticJS object

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

How to manually define vertices in box2D javascript?

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.

Categories

Resources