EaselJS: Update shape color on property change - javascript

I am writing a simple game in JS using EaselJS. I try to keep everything object-oriented to keep in sync state of game, state of EaselJS objects and what is displayed on my canvas. I would like to have possibility to change stroke color of shapes that are displayed on canvas by changing their attributes. I've found in docs append() here, but I can't get it working.
Here's what I've achieved so far:
Shape definition:
var bLetter = new createjs.Shape();
bLetter.graphics.append({exec: setPoweredState});
bLetter.graphics.moveTo(0, 0)
.lineTo(0, segSize * 2)
.arc(circSize, segSize * 2, circSize, Math.PI, Math.PI + 0.0001, true);
setPoweredState function - When i set bLetter.powered = true, the line color should change:
setPoweredState = function(ctx, shape) {
if(shape.powered) {
shape.color = consts.COLOR_LINE_ACTIVE;
} else {
shape.color = consts.COLOR_LINE_INACTIVE;
}
shape.graphics.beginStroke(shape.color).setStrokeStyle(consts.STROKE_SIZE, 'round', 'round');
}
When I set bLetter.powered = true and I check bLetter.color it seems that the function is executed - the bLetter.color property changes. However, the bLetter object on canvas is not updated. What's more, it's not drawn at all - probably I am using append() in incorrect way. What am I missing?
BTW: I omit the code with initializing createjs.Stage on canvas and adding bLetter as it's child, I don't think it's an issue, the shape is drawn correctly, only color won't change.

The issue is that you are continually appending new stroke / strokestyle commands to the end of the graphics queue, so they have no effect on the preceding paths.
The easiest approach in my opinion would be to save off the command as Lanny suggested, and modify its style in your setPoweredState method.
Here's an example of the above, implement with minimal modifications to your approach:
https://jsfiddle.net/u4o4hahw/

Instead of using append, consider just storing off commands to modify.
Here is another question that I answered outlining how it works: Injecting a new stroke color into a shape, and here is a blog post: http://blog.createjs.com/new-command-approach-to-easeljs-graphics/
Basically, you can store any command, then change its properties later:
var cmd = shape.graphics.beginFill("red").command;
shape.graphics.otherInstructionsHere();
// Later
cmd.style = "blue";
Here is a link to the docs on the Fill command used in the sample code: http://createjs.com/docs/easeljs/classes/Graphics.Fill.html

Related

Is it possible to hide the segment squares on paths in paperjs

When creating path elements in paperJS, the default behavior creates small squares at the intersection of each segment. Is there a way to maintain the default blue path line but hide the squares? A property that can be used to show/hide them?
Draw a line to see an example
http://paperjs.org/examples/path-simplification/
I wondered the same thing a some point but never tried to figure it out until your question. I cant seem to find any documentation on this but it worked on jsfiddle. Try this:
const scope = new paper.PaperScope();
project = new scope.Project(canvasElem);
project.options.handleSize = 0;
Found documentation
I believe the correct approach would be to set this value in scope.settings;
const scope = new paper.PaperScope();
scope.settings.handleSize = 0;
PaperScope.settings.handleSize

draw function not looping as expected

I'm a beginner on here, so apologies in advance for naivety. I've made a simple image on Brackets using Javascript, trying to generate circles with random x and y values, and random colours. There are no issues showing when I open the browser console in Developer Tools, and when I save and refresh, it works. But I was expecting the refresh to happen on a loop through the draw function. Any clues as to where I've gone wrong?
Thanks so much
var r_x
var r_y
var r_width
var r_height
var x
var y
var z
function setup()
{
r_x = random()*500;
r_y = random()*500;
r_width = random()*200;
r_height = r_width;
x = random(1,255);
y= random(1,255);
z= random(1,255);
createCanvas(512,512);
background(255);
}
function draw()
{
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
Brackets.io is just your text editor (or IDE if you want to be technical) - so we can remove that from the equation. The next thing that baffles me is that something has to explicitly call your draw() method as well as the setup() method -
I'm thinking that you're working in some sort of library created to simplify working with the Canvas API because in the setup() method you're calling createCanvas(xcord,ycord) and that doesn't exist on it's own. If you want to rabbit hole on that task check out this medium article, it walks you thru all the requirements for creating a canvas element and then drawing on that canvas
Your also confirming that you're drawing at least 1 circle on browser refresh so i think all you need to focus on is 1)initiating your code on load and 2)a loop, and we'll just accept there is magic running in the background that will handle everything else.
At the bottom of the file you're working in add this:
// when the page loads call drawCircles(),
// i changed the name to be more descriptive and i'm passing in the number of circles i want to draw,
// the Boolean pertains to event bubbling
window.addEventListener("load", drawCircles(73), false);
In your drawCircles() method you're going to need to add the loop:
// im using a basic for loop that requires 3 things:
// initialization, condition, evaluation
// also adding a parameter that will let you determine how many circles you want to draw
function drawCircles(numCircles) {
for (let i = 0; i < numCircles; i++) {
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
}
here's a link to a codepen that i was tinkering with a while back that does a lot of the same things you are
I hope that helps - good luck on your new learning venture, it's well worth the climb!
Thank you so much for your help! What you say makes sense - I basically deleted the equivalent amount of code from a little training exercise downloaded through coursera, thinking that I could then essentially use it as an empty sandpit to play in. But there's clearly far more going on under the hood!
Thanks again!

How to address a shape drawn on a HTML5 canvas and change its properties?

I am beginning to explore the HTML5 canvas, and I apologize in advance for the naivety of my question. Using Flash CC, I have generated a canvas with a rectangle on it:
(function (lib, img, cjs, ss) {
var p; // shortcut to reference prototypes
// library properties:
lib.properties = {
width: 550,
height: 400,
fps: 24,
color: "#FFFFFF",
manifest: []
};
// symbols:
// stage content:
(lib.canvas_test = function() {
this.initialize();
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.beginFill().beginStroke("#669966")
.setStrokeStyle(1,1,1).moveTo(-94,-62).lineTo(94,-62).lineTo(94,62).lineTo(-94,62).closePath();
this.shape.setTransform(198,136);
this.shape_1 = new cjs.Shape();
this.shape_1.graphics.beginFill("#FF933C")
.beginStroke().moveTo(-94,62).lineTo(-94,-62).lineTo(94,-62).lineTo(94,62).closePath();
this.shape_1.setTransform(198,136);
this.addChild(this.shape_1,this.shape);
}).prototype = p = new cjs.Container();
p.nominalBounds = new cjs.Rectangle(378,273,190,126);
})(lib = lib||{}, images = images||{}, createjs = createjs||{}, ss = ss||{});
var lib, images, createjs, ss;
Now I am stuck. How can I retrieve (and change) the color of the rectangle using a Javascript function? I had hoped that the shapes would simply be children of the canvas, but this does not seem to be the case.
The earlier answers are correct about Canvas being basically a bitmap, but EaselJS gives you a retained graphics mode, so you can change properties and update the stage/canvas to reflect them.
You are using Flash export to generate your content, so you should be able to access your elements via the exportRoot, which is created in the HTML. This is essentially the Flash "stage", represented by an EaselJS container that is defined by canvas_test in your exported library.
exportRoot = new lib.canvas_test();
You can see in the canvas_test code, each "child" is defined. Any graphics are wrapped in EaselJS Shape instances. There are also classes for handling groups (Containers), Bitmaps, Text, and animations (MovieClips).
Here is your exported code above put added to the stage:
http://jsfiddle.net/lannymcnie/b5me4xa2/
It is easy to modify shapes once they are created, but you have to define them with that in mind. The Flash export doesn't really provide you this capability, since it just exports everything as a single, chained graphics instructions list. You can however introspect it fairly easily to find the commands you want to modify. Warning: This requires EaselJS 0.7.0+ in order to work. Earlier versions will not work with this approach
The demo you provided has a single Rectangle. Unfortunately there is a bug in the current version of Flash that exports it as 2 shapes, one for the stroke, and another for the fill. This example will modify the stroke.
var shape = exportRoot.shape; // Access the shape instance that has the stroke
var stroke = shape.graphics._stroke;
stroke.style = "#ff0000"; // Set to red.
To do the fill, you can do the same thing on shape_1, but affect the _fill instead. Here is an updated sample
You can also access any of the instructions, and affect their properties. You can see a full command list in the Graphics docs (see the sidebar for the full list). Here is a quick sample modifying the first moveTo command on the stroke:
var shape = exportRoot.shape;
shape.graphics._activeInstructions[0].x = -110;
You can see a sample of that code here: http://jsfiddle.net/lannymcnie/b5me4xa2/2/ -- You will have to modify both fill and stroke to move them both :)
Canvas is basically a bitmap, it has no children. An SVG works more like you're imagining but a canvas just has pixels. If you want to change a canvas you're either going to have to go through it and find the pixels, or create a javascript object representing your drawing object (the rectangle), keep it separate from your canvas background, and redraw the the background and object when there are any changes.
[Added]
I'm not familiar with Flash CC, but as pointed out in the comment, perhaps there is some capability there already to do what the commenter and myself are describing - I'm afraid I don't know.

Drawing a Line in a html5 canvas using EaselJS

I am very new to Easel and HTML5 itself. I am trying to draw a line using on a canvas using EaselJS. The X- Co ordinate is fixedd to 100 and the Y-Co ordinate is got from a array list. The code that i have written is given below. Could please someone let me know where i am going wrong?
function myFunction(attachPoint)
{
//Code for canvas creation is written here.[Not shown];
//created a stage.
stage = new createjs.Stage(canvas.domElement());
//3. create some shapes.MagnitudeLessThanTwo is the array where we get the YAxis Coordinates from
alert("The lenght before function is"+MagnitudeLessThanTwo.length);
myShape = new drawLineGraph(MagnitudeLessThanTwo);
//4. finally add that shape to the stage
stage.addChild(myShape);
//5. set up the ticker
if (!createjs.Ticker.hasEventListener("tick")) {
createjs.Ticker.addEventListener("tick", ourTickFunction);
};
};
function drawLineGraph(dataList)
{
this.index=0;//To keep the track of the index of the array from which we get the Y Axis.
var graphics = new createjs.Graphics();
graphics.setStrokeStyle(1);
graphics.beginStroke("white");
graphics.moveTo(50,(dataList[this.index].magnitude)*100);
graphics.lineTo(50,(dataList[(this.index)++].magnitude)*100);
createjs.Shape.call(this,graphics);
this.tick = function() {
graphics.moveTo(100,(dataList[this.index].magnitude)*100);
graphics.lineTo(100,(dataList[(this.index)++].magnitude)*100);
stage.addChild(graphics);
};
};
drawLineGraph.prototype = new createjs.Shape(); //set prototype
drawLineGraph.prototype.constructor = drawLineGraph; //fix constructor pointer
I am getting the following Error.
"Object [object Object] has no method 'isVisible'"- This is inside the EaselJS Library.
There are a few issues here. The error you are seeing is because you are adding the Graphics to the Stage, and not the Shape.
The other issue is how the Graphics are modified in the tick:
this.tick = function() {
graphics.moveTo(100,(dataList[this.index].magnitude)*100);
graphics.lineTo(100,(dataList[(this.index)++].magnitude)*100);
stage.addChild(graphics);
};
You only need to add your Shape to the stage one time, and it will redraw your graphics each time every time the Stage is updated. Your tick call is adding new Graphics instructions every frame, so it will stack all those calls up, and eventually be really slow.
Make sure you clear your Graphics before you draw new things to it, unless you are trying to create an additive effect (and if you are, perhaps look into caching/updateCache to make it performant). Check out the "curveTo" and "updateCache" examples in the GitHub repository for usage.
Once you have added the Shape to the stage instead of the Graphics, feel free to post some follow up questions, and I can try and assist further.
Cheers :)

RectangularRangeIndicator format like triangular using dojo

I'm trying to add an indicator to my vertical gauge but the format of the indicator is like a triangle, but I want it a large line.
This is JSFIDDLE example.
The code :
require(['dojo/parser', 'dojox/dgauges/components/default/VerticalLinearGauge','dojox/dgauges/RectangularRangeIndicator', 'dojo/domReady!'], function (parser, VerticalLinearGauge) {
parser.parse();
var ri = new dojox.dgauges.RectangularRangeIndicator();
ri.set("start",0 );
ri.set("value", 30);
ri.set("startThickness",100);
ri.set("endThickness",100);
gauge.getElement("scale").addIndicator("ri", ri, false);
});
This is a bug, it will be fixed in next releases (1.8.x and 1.9).
See https://github.com/dmandrioli/dgauges/issues/15
As a workaround, you can redefine the bad method like this:
myRangeIndicator._defaultVerticalShapeFunc =
function(indicator, group, scale, startX,
startY, endPosition, startThickness, endThickness,
fill, stroke){ ... }
See this workaround in action at http://jsfiddle.net/BFPuL/5/
I think that the properties are startThickness and endThickness (no "stroke" at the end). However, I still don't get one solid line when setting these properties to equal values like one would expect. It seems as though something odd (perhaps a bug) is happening with the way that the startThickness property is handled.
This problem has me interested, so I'll try to set aside some time later to dig into the source to see what the real issue is, but for now I can offer you a dirty workaround. The RectangularRangeIndicator is drawn using the dojox/gfx module, and the outline of the indicator drawn is controlled by the stroke property. So, if you want, you can do something like:
var ri = new dojox.dgauges.RectangularRangeIndicator();
ri.set("start",0 );
ri.set("value", 30);
ri.set("startThickness", 0);
ri.set("endThickness", 0);
ri.set("stroke", {color: "red", width: 2.5});
ri.set("paddingLeft", 7); // Default is 10, set this to whatever works for you.
This will appear to draw straight line (which is really the border of an extremely thin shape). Check out how it looks in a real example. Again, I understand that this is not the best solution since it is more of a dirty trick, but it is a way around what appears to be a bug in the code that renders a range indicator.

Categories