If statement to change text colour - actionscript-3

for(var temp:int = 0;temp<recipeNum;temp++)
{
if ((temp == 1) || (temp == 2) || (temp == 6) || (temp == 9))
{
textRecipe.textColor = 0x0000FF;
}
else
{
textRecipe.textColor = 0x000000;
}
textRecipe.text += "\n" + recipe[temp];
addChild(textRecipe);
}
The problem with this code all the text on screen is black. I want temp 1,2,6,9 to be blue, any solutions.

If I'm not wrong you're using only one TextField named textRecipe.
Note that, even if you add it recipeNum times to the stage, it's always the same object.
Assigning textColor property, it modifies the color of the entire text, so the last color assigned (probably black) will be the color of the entire text.
Either use more than one TextField or use a TextFormat to assign color to a part of the text:
var myFormat = new TextFormat();
myFormat.color = 0x0000FF;
textRecipe.setTextFormat(myFormat, 5, 8); //sets color blue to chars from 5 to 8
Let me know if you need more help.

Related

How to place each shapes right next to each other? And glow the shapes with thick outline

This is my sketch.js
// Standard "run once" component of Processing/P5JS idiom
function setup() {
createCanvas(400, 400);
background("#CCFFFF");
// Not providing any interactivity right now
noLoop();
console.log("Starting...");
myQuilt = new Quilt(4, 4, 100, color(0, 204, 128));
let blocks = [];
let backColor = color(176,224,230,1);
let color1 = color("#A60D41");
let color2 = color("#937109");
let color3 = color("#0B8710");
let color4 = color("#2B1C07");
let color5 = color("#FD9708");
let color6 = color("#FFFFFF");
// Create the 2d array
for (let row = 0; row < 4; row++) {
blocks[row] = new Array(4);
}
// Instantiate and add blocks to the Quilt
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 4; col++) {
// I am adding a single kind of block here
// to each row and column. Add blocks you
// make and blocks you download from others
// in your Quilt.
if (row == 0) {
blocks[row][col] = new circles(100, 100, backColor, color2, color3);
} else if(row == 1)
{
blocks[row][col] = new LogCabin(100, 100, backColor, color1, color2);
}
else if(row == 2)
{
blocks[row][col] = new FlowerGarden(100, 100, backColor, color3, color4);
}
else if(row == 3)
{
blocks[row][col] = new EightPointStar(100, 100, backColor, color4, color5);
}
// Since I built a simple rotation flag into
// my FourPatch block, here I am rotating
// every third row. You do what you like.
myQuilt.addBlock(blocks[row][col], row, col);
}
}
// Draw it now
myQuilt.render();
}
This is what i have so far. I need to put in one line 1circle, 1Logcabin, then 1flowergarden, 1EighthPoint star.
![Text](https://i.stack.imgur.com/uDP5y.png
This Picture above is an example how i want mine to look like also the glowing colors.
![Text](https://i.stack.imgur.com/tCZJL.png

How to create a matrix in a loop for hittesting with colors without duplicate colors

I am trying to create a matrix with color hexagons that will allow for object hit-testing. This color matrix will sit behind a regular hexagon matrix(one without the matrix cells colored). I will mouse over and check for the color in the hidden matrix to indicate which object my mouse is over so I can simulate object detection. This should be straight forward but for some reason I cannot get the expected results.
I have a parent loop which loops through creating rows of the matrix. Each iteration calls the following function to paint the hexagon(which is defined in a collection of points made available through a hexagon service).
constructor(
private hexagons: HexagonService,
private state: StateService,
private randomColors: RandomColorService,
private drawingContextService: DrawingContextService) {
}
async DrawHexagonAsync(hidecolors: boolean): Promise<any> {
const color = this.randomColors.next();
let strokestyle = this.state.strokeStyle;
const context = this.drawingContextService.context;
console.log(color); // Look for duplicates in console
if (hidecolors) {
strokestyle = `#fff`;
}
context.strokeStyle = strokestyle;
context.lineWidth = this.state.lineWidth;
context.fillStyle = color;
context.lineJoin = 'round';
context.lineCap = 'round';
const points = this.hexagons.getHexagonPoints();
context.beginPath();
let x = this.drawingContextService.location.x + points[0].x;
let y = this.drawingContextService.location.y + points[0].y
context.moveTo(x,y);
// move to the start point
for (let i = 1; i < points.length; i++) {
x = points[i].x + this.drawingContextService.location.x;
y = points[i].y + this.drawingContextService.location.y;
context.lineTo(x, y);
context.stroke();
}
context.fill();
context.closePath();
}
At first glance it looks like it is working and creates a lovely hex matrix like the following:
At closer inspection, I noticed that some of the contiguous items get rendered as duplicate colors. Since, I need unique colors for hit-testing this will not do. I use a color service to iterate through and create unique colors.
// color service.
#Injectable({provideIn: 'root'})
export class RandomColorService {
colors: string[] = [];
index = 0;
constructor() {
while (this.colors.length < 5000) {
let random = () => {
let n = Math.random() * 256;
return Math.floor(n).toString(16);
}
// make sure there are no duplicate colors.
const color = `#${random()}${random()}${random()}`;
if (!this.colors.includes(color)) {
this.colors.push(color);
}
}
}
public next() {
if (this.index >= 5000) {
this.index = 0;
}
return this.colors[this.index++];
}
}
Initially, I put the checking code to make sure that the colors were unique but the same duplicate color problem occurs with or without the code check. The next function just returns the unique colors as needed and moves to the next.
I even put a console.log in the code to check and I don't see any duplicate log messages, yet the colors are clearly duplicates.
Using the following function against the colors clearly indicates that the colors are not similar(but in fact duplicate)
// Gets a pixel from the canvas and extracts the color.
onclick(evt) {
var pixelData = this.drawing.context.getImageData(evt.x, evt.y, 1, 1).data;
var hex = "#" + ("000000" + this.rgbToHex(pixelData[0], pixelData[1], pixelData[2])).slice(-6);
console.log(hex);
}
rgbToHex(r, g, b) {
if (r > 255 || g > 255 || b > 255)
throw "Invalid color component";
return ((r << 16) | (g << 8) | b).toString(16);
}
So naturally the question is, what am I missing?
The bug is in the color service. The numbers need to be padded with '0'. If the color is not 6 digits then the color change fails and the previous color is retained and used.
return Math.floor(n).toString(16).padStart(2, '0');
// color service.
#Injectable({provideIn: 'root'})
export class RandomColorService {
colors: string[] = [];
index = 0;
constructor() {
while (this.colors.length < 5000) {
let random = () => {
let n = Math.random() * 256;
return Math.floor(n).toString(16);
}
// make sure there are no duplicate colors.
const color = `#${random()}${random()}${random()}`;
if (!this.colors.includes(color)) {
this.colors.push(color);
}
}
}
public next() {
if (this.index >= 5000) {
this.index = 0;
}
return this.colors[this.index++];
}
}

How to determine shape fill color in AS3?

I have a circle inside a MovieClip on stage with an instance name holder. I want to get color of that circle.
I am successfully targeting that circle as shown in code. I can change its color using transform, but I cannot find a way to actually check its color.
holder.getChildAt(0);
OK, as I said in my reply, at the end, this is doing what I need. It could be a bit simplified and optimized, but, as far as my needs are going, it is fast enough! :)
function decimalToHex(decimal: int, padding: int = 2): String {
var hex: String = Number(decimal).toString(16);
while (hex.length < padding) {
hex = "0" + hex;
}
return hex.toUpperCase();
}
function getColor(what: Object):void {
var obj = what.getChildAt(0);
var bmd: BitmapData = new BitmapData(obj.width, obj.height, true, 0x00ffffff);
//In the 0x00ffffff color, leading two zeros are alpha channel
bmd.draw(obj);
var img = new Bitmap(bmd);
var stp = "";
for (var l: uint = 0; l < img.height && stp == ""; l++) {
for (var m: uint = 0; m < img.width && stp == ""; m++) {
var color = decimalToHex(bmd.getPixel32(m, l), 8);
if (int(parseInt(color.substr(0, 2), 16)) > 0) {
color = "#" + color.substr(2);
stp = "stop";
// Display color in a text box named as "what"'s name + letter "c"
param.getChildByName(what.name + "c").text = color;
}
}
}
}
getColor(holder); //As in question, my shape is inside it's holder

HTML5 Canvas - Anti-aliasing and Paint Bucket / Flood Fill

Having trawled Stack Overflow and Google it seems to me that there is no way to disable antialiasing when drawing lines on an HTML5 canvas.
This makes for nice looking lines, but causes me a problem when it comes time to applying a paint bucket / flood fill algorithm.
Part of my application requires that users draw on a canvas, freestyle drawing with basic tools like line size, color... and a paint bucket.
Because lines are rendered with antialiasing they are not a consistent color... with that in mind consider the following:
Draw a thick line in black
Decide at some point later that the line should be red
Apply flood fill to black line
My flood fill algorithm fills the bulk of the line with red, but the edges that were antialiased are detected as being outside the area that should be filled... hence remain (greys / blues(?) left over from the black line).
The flood fill algorithm does not incorporate something akin to 'tolerance' like Photoshop does... I have considered something like that but am unsure it would help as I don't think the anti-aliasing does something simple like render grey next to a black line, I think it's more advanced than that and the anti-aliasing takes into consideration the surrounding colors and blends.
Does anyone have any suggestions as to how I can end up with a better paint bucket / flood fill that COMPLETELY flood fills / replaces an existing line or section of a drawing?
If you simply want to change a color of a line: don't use bucket paint fill at all.
Store all your lines and shapes as objects/arrays and redraw them when needed.
This not only allow you to change canvas size without losing everything on it, but to change a color is simply a matter of changing a color property on your object/array and redraw, as well as scaling everything based on vectors instead of raster.
This will be faster than a bucket fill as redrawing is handled in most part internally and not by pixel-by-pixel in JavaScript as is needed with a bucket fill.
That being said: you cannot, unfortunately, disable anti-alias for shapes and lines, only for images (using the imageSmoothingEnabled property).
An object could look like this:
function myLine(x1, y1, x2, y2, color) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.color = color;
return this;
}
And then allocate it by:
var newLine = new myLine(x1, y1, x2, y2, color);
Then store this to an array:
/// globally:
var myLineStack = [];
/// after x1/x2/y1/y2 and color is achieved in the draw function:
myLineStack.push(new myLine(x1, y1, x2, y2, color));
Then it is just a matter of iterating through the objects when an update is needed:
/// some index to a line you want to change color for:
myLineStack[index].color = newColor;
/// Redraw all (room for optimizations here...)
context.clearRect( ... );
for(var i = 0, currentLine; currentLine = myLineStack[i]; i++) {
/// new path
context.beginPath();
/// set the color for this line
context.strokeStyle = currentLine.color;
/// draw the actual line
context.moveTo(currentLine.x1, currentLine.y1);
context.lineTo(currentLine.x2, currentLine.y2);
context.stroke();
}
(For optimizations you can for example clear only the area that needs redraw and draw a single index. You can also group lines/shapes with the same colors and draw then with a single setting of strokeStyle etc.)
You can not always redraw the canvas, you may have used filters that can not be reversed, or just use so many fill and stroke calls it would be impractical to redraw.
I have my own flood fill based on a simple fill stack that paints to a tolerances and does its best to lessen anti-aliasing artifacts. Unfortunately if you have anti-aliasing on repeated fills will grow the filled region.
Below is the function, adapt it as suited, it is a direct lift from my code with comments added.
// posX,posY are the fill start position. The pixel at the location is used to test tolerance.
// RGBA is the fill colour as an array of 4 bytes all ranged 0-255 for R,G,B,A
// diagonal if true the also fill into pixels that touch at the corners.
// imgData canvas pixel data from ctx.getImageData method
// tolerance Fill tolerance range 0 only allow exact same colour to fill to 255
// fill all but the extreme opposite.
// antiAlias if true fill edges to reduce anti-Aliasing artifacts.
Bitmaps.prototype.floodFill = function (posX, posY, RGBA, diagonal,imgData,tolerance,antiAlias) {
var data = imgData.data; // image data to fill;
antiAlias = true;
var stack = []; // paint stack to find new pixels to paint
var lookLeft = false; // test directions
var lookRight = false;
var w = imgData.width; // width and height
var h = imgData.height;
var painted = new Uint8ClampedArray(w*h); // byte array to mark painted area;
var dw = w*4; // data width.
var x = posX; // just short version of pos because I am lazy
var y = posY;
var ind = y * dw + x * 4; // get the starting pixel index
var sr = data[ind]; // get the start colour tha we will use tollerance against.
var sg = data[ind+1];
var sb = data[ind+2];
var sa = data[ind+3];
var sp = 0;
var dontPaint = false; // flag to indicate if checkColour can paint
// function checks a pixel colour passes tollerance, is painted, or out of bounds.
// if the pixel is over tollerance and not painted set it do reduce anti alising artifacts
var checkColour = function(x,y){
if( x<0 || y < 0 || y >=h || x >= w){ // test bounds
return false;
}
var ind = y * dw + x * 4; // get index of pixel
var dif = Math.max( // get the max channel differance;
Math.abs(sr-data[ind]),
Math.abs(sg-data[ind+1]),
Math.abs(sb-data[ind+2]),
Math.abs(sa-data[ind+3])
);
if(dif < tolerance){ // if under tollerance pass it
dif = 0;
}
var paint = Math.abs(sp-painted[y * w + x]); // is it already painted
if(antiAlias && !dontPaint){ // mitigate anti aliasing effect
// if failed tollerance and has not been painted set the pixel to
// reduce anti alising artifact
if(dif !== 0 && paint !== 255){
data[ind] = RGBA[0];
data[ind+1] = RGBA[1];
data[ind+2] = RGBA[2];
data[ind+3] = (RGBA[3]+data[ind+3])/2; // blend the alpha channel
painted[y * w + x] = 255; // flag pixel as painted
}
}
return (dif+paint)===0?true:false; // return tollerance status;
}
// set a pixel and flag it as painted;
var setPixel = function(x,y){
var ind = y * dw + x * 4; // get index;
data[ind] = RGBA[0]; // set RGBA
data[ind+1] = RGBA[1];
data[ind+2] = RGBA[2];
data[ind+3] = RGBA[3];
painted[y * w + x] = 255; // 255 or any number >0 will do;
}
stack.push([x,y]); // push the first pixel to paint onto the paint stack
while (stack.length) { // do while pixels on the stack
var pos = stack.pop(); // get the pixel
x = pos[0];
y = pos[1];
dontPaint = true; // turn off anti alising
while (checkColour(x,y-1)) { // find the bottom most pixel within tolerance;
y -= 1;
}
dontPaint = false; // turn on anti alising if being used
//checkTop left and right if alowing diagonal painting
if(diagonal){
if(!checkColour(x-1,y) && checkColour(x-1,y-1)){
stack.push([x-1,y-1]);
}
if(!checkColour(x+1,y) && checkColour(x+1,y-1)){
stack.push([x+1,y-1]);
}
}
lookLeft = false; // set look directions
lookRight = false; // only look is a pixel left or right was blocked
while (checkColour(x,y)) { // move up till no more room
setPixel(x,y); // set the pixel
if (checkColour(x - 1,y)) { // check left is blocked
if (!lookLeft) {
stack.push([x - 1, y]); // push a new area to fill if found
lookLeft = true;
}
} else
if (lookLeft) {
lookLeft = false;
}
if (checkColour(x+1,y)) { // check right is blocked
if (!lookRight) {
stack.push([x + 1, y]); // push a new area to fill if found
lookRight = true;
}
} else
if (lookRight) {
lookRight = false;
}
y += 1; // move up one pixel
}
// check down left
if(diagonal){ // check for diagnal areas and push them to be painted
if(checkColour(x-1,y) && !lookLeft){
stack.push([x-1,y]);
}
if(checkColour(x+1,y) && !lookRight){
stack.push([x+1,y]);
}
}
}
// all done
}
There is a better way that gives high quality results, the above code can be adapted to do this by using the painted array to mark the paint edges and then after the fill has completed scan the painted array and apply a convolution filter to each edge pixel you have marked. The filter is directional (depending on which sides are painted) and the code too long for this answer. I have pointed you in the right direction and the infrastructure is above.
Another way to improve the image quality is to super sample the image you are drawing to. Hold a second canvas that is double the size of the image being painted. Do all you drawing to that image and display it to the user on another canvas with CTX.imageSmoothingEnabled and ctx.setTransform(0.5,0,0,0.5,0,0) half size, when done and the image is ready half its size manually with the following code (don't rely on canvas imageSmoothingEnabled as it gets it wrong.)
Doing this will greatly improve the quality of your final image and with the above fill almost completely eliminate anti-aliasing artifacts from flood fills.
// ctxS is the source canvas context
var w = ctxS.canvas.width;
var h = ctxS.canvas.height;
var data = ctxS.getImageData(0,0,w,h);
var d = data.data;
var x,y;
var ww = w*4;
var ww4 = ww+4;
for(y = 0; y < h; y+=2){
for(x = 0; x < w; x+=2){
var id = y*ww+x*4;
var id1 = Math.floor(y/2)*ww+Math.floor(x/2)*4;
d[id1] = Math.sqrt((d[id]*d[id]+d[id+4]*d[id+4]+d[id+ww]*d[id+ww]+d[id+ww4]*d[id+ww4])/4);
id += 1;
id1 += 1;
d[id1] = Math.sqrt((d[id]*d[id]+d[id+4]*d[id+4]+d[id+ww]*d[id+ww]+d[id+ww4]*d[id+ww4])/4);
id += 1;
id1 += 1;
d[id1] = Math.sqrt((d[id]*d[id]+d[id+4]*d[id+4]+d[id+ww]*d[id+ww]+d[id+ww4]*d[id+ww4])/4);
id += 1;
id1 += 1;
d[id1] = Math.sqrt((d[id]*d[id]+d[id+4]*d[id+4]+d[id+ww]*d[id+ww]+d[id+ww4]*d[id+ww4])/4);
}
}
ctxS.putImageData(data,0,0); // save imgData
// grab it again for new image we don't want to add artifacts from the GPU
var data = ctxS.getImageData(0,0,Math.floor(w/2),Math.floor(h/2));
var canvas = document.createElement("canvas");
canvas.width = Math.floor(w/2);
canvas.height =Math.floor(h/2);
var ctxS = canvas.getContext("2d",{ alpha: true });
ctxS.putImageData(data,0,0);
// result canvas with downsampled high quality image.

Insane Graphics.lineStyle behavior

I'd like some help with a little project of mine.
Background:
i have a little hierarchy of Sprite derived classes (5 levels starting from the one, that is the root application class in Flex Builder). Width and Height properties are overriden so that my class always remembers it's requested size (not just bounding size around content) and also those properties explicitly set scaleX and scaleY to 1, so that no scaling would ever be involved. After storing those values, draw() method is called to redraw content.
Drawing:
Drawing is very straight forward. Only the deepest object (at 1-indexed level 5) draws something into this.graphics object like this:
var gr:Graphics = this.graphics;
gr.clear();
gr.lineStyle(0, this.borderColor, 1, true, LineScaleMode.NONE);
gr.beginFill(0x0000CC);
gr.drawRoundRectComplex(0, 0, this.width, this.height, 10, 10, 0, 0);
gr.endFill();
Further on:
There is also MouseEvent.MOUSE_WHEEL event attached to the parent of the object that draws. What handler does is simply resizes that drawing object.
Problem:
Screenshot
When resizing sometimes that hairline border line with LineScaleMode.NONE set gains thickness (quite often even >10 px) + it quite often leaves a trail of itself (as seen in the picture above and below blue box (notice that box itself has one px black border)). When i set lineStile thickness to NaN or alpha to 0, that trail is no more happening.
I've been coming back to this problem and dropping it for some other stuff for over a week now.
Any ideas anyone?
P.S. Grey background is that of Flash Player itself, not my own choise.. :D
As requested, a bit more:
Application is supposed to be a calendar-timeline with a zooming "feature" (project for a course at university). Thus i have these functions that have something to do with resizing:
public function performZoom():void
{
// Calculate new width:
var newDayWidth:Number = view.width / 7 * this.calModel.zoom;
if (newDayWidth < 1)
{
newDayWidth = 1;
}
var newWidth:int = int(newDayWidth * timeline.totalDays);
// Calculate day element Height/Width ratio:
var headerHeight:Number = this.timeline.headerAllDay;
var proportion:Number = 0;
if (this.view.width != 0 && this.view.height != 0)
{
proportion = 1 / (this.view.width / 7) * (this.view.height - this.timeline.headerAllDay);
}
// Calculate new height:
var newHeight:int = int(newDayWidth * proportion + this.timeline.headerAllDay);
// Calculate mouse position scale on X axis:
var xScale:Number = 0;
if (this.timeline.width != 0)
{
xScale = newWidth / this.timeline.width;
}
// Calculate mouse position scale on Y axis:
var yScale:Number = 0;
if (this.timeline.height - this.timeline.headerAllDay != 0)
{
yScale = (newHeight - this.timeline.headerAllDay) / (this.timeline.height - this.timeline.headerAllDay);
}
this.timeline.beginUpdate();
// Resize the timeline
this.timeline.resizeElement(newWidth, newHeight);
this.timeline.endUpdate();
// Move timeline:
this.centerElement(xScale, yScale);
// Reset timeline local mouse position:
this.centerMouse();
}
public function resizeElement(widthValue:Number, heightValue:Number):void
{
var prevWidth:Number = this.myWidth;
var prevHeight:Number = this.myHeight;
if (widthValue != prevWidth || heightValue != prevHeight)
{
super.width = widthValue;
super.height = heightValue;
this.scaleX = 1.0;
this.scaleY = 1.0;
this.myHeight = heightValue;
this.myWidth = widthValue;
if (!this.docking)
{
this.origHeight = heightValue;
this.origWidth = widthValue;
}
this.updateAnchorMargins();
onResizeInternal(prevWidth, prevHeight, widthValue, heightValue);
}
}
Yes. I know.. a lot of core, and a lot of properties, but in fact most of the stuff has been disabled at the end and the situation is as described at the top.
this didn't work:
gr.lineStyle(); // Reset line style
Can we see your resizing code?
Also try clearing your line style as well as your fill:
gr.lineStyle(0, this.borderColor, 1, true, LineScaleMode.NONE);
gr.beginFill(0x0000CC);
gr.drawRoundRectComplex(0, 0, this.width, this.height, 10, 10, 0, 0);
gr.endFill();
gr.lineStyle();//<---- add this line
I don't know whether it's flash bug or what it is, but i finally found the solution.
The thing is that in my case when resizing in a nutshell you get like this:
this.width = this.stage.stageWidth / 7 * 365;
When i switch to maximized window this.width gains value 86k+. When i added this piece of code to draw horizontal line, it fixed itself:
var recWidth:Number = this.width;
var i:int;
var newEnd:Number = 0;
for (i = 1; newEnd < recWidth; i++)
{
newEnd = 100 * i;
if (newEnd > recWidth)
{
newEnd = recWidth;
}
gr.lineTo(newEnd, 0);
}
I don't know what is going on.. This is inconvenient...