I had a quick question regarding the ctx function stroke along with the usage of rect. In my code, I draw a rect and fill it with red. I want to also add a green border around the rect, but when I use stroke it seems to create a transparent border, rather than a fully solid line. Why does it do this by default?
Img of result:
My code:
var ctx = Canvas.ctx;
ctx.beginPath();
ctx.rect(this.x, this.y, this.width, this.height);
/*
* CONTAINER
*/
ctx.fillStyle = this.primaryColor;
ctx.fill();
/*
* CONTAINER BAR
*/
if(this.borderColor){
ctx.strokeStyle = this.borderColor;
ctx.stroke();
}
/*
* INNER BAR
*/
var per = this.percent;
if(per > 0){
//the width of the actual loading bar that appears
//inside the entire box
var innerWidth = Math.floor(this.width*(per/100));
ctx.fillStyle = this.secondaryColor;
ctx.fillRect(this.x+1, this.y+1, innerWidth-2, this.height-2);
}
/*
* TEXT
*/
if(this.text){
ctx.textAlign = this.textAlign;
ctx.font = this.font;
ctx.fillStyle = this.textColor;
ctx.fillText(this.text, this.textX, this.textY);
}
Canvas draws its lines straddling your pixel coordinate. So a lineWidth=1 vertical line at x=20 will be drawn from 19.5 to 20.5.
To help clarify your rectangle follow these 2 hints:
Assign the rect's x,y,width,height as integers
Set translate(0.50,0.50) before drawing the rect(s) and unset translate(-0.50,-0.50) afterwards
You can read more about the "why?" here:
http://diveintohtml5.info/canvas.html
Note that these hints help with vertical & horizontal lines, but don't help angled lines & curves.
Related
I am creating one geometry at location (0,0,0) but projecting at some other location (for ex. #50,50,50). If the point (0,0,0) is going out of canvas, then geometry is hiding.
Is there any way to always render it on canvas?
How far off the edge does the origin need to be?
You could make the canvas larger than you need, than mask the areas on the edge such that only the center area shows. That way when the origin goes off the side, it will still technically be on the canvas, and the projected geometry will be in the visible area. I expect you will only need a buffer space equal to projection offset.
See here for an example of applying a mask: https://jsfiddle.net/shawnoakley/n1368qr0/2/
Example code:
var context = document.getElementById('canvas').getContext('2d');
// Mask color
context.fillStyle = '#000';
// Image proportions
context.fillRect(0,0,600,400);
var unmaskedImage = function(x, y, radius){
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
context.restore();
};
unmaskedImage(300, 300, 300);
Briefly, I am having a problem performing a simple stroke operation on arabic text in an html5 2D canvas.
Arabic text has this property of characters changing forms and merging together when they're next to each other. Apparently, how js handles text stroke is by taking every character by itself and operating on them separately. When the characters are then rendered to the screen, the boundaries of characters becomes visible resulting in leaking stroke colors at the joints.
On the left is the result produced by Javascript's stroke function. On the right is a correct result created with Photoshop (different font).
Is there a way around this?
Your problem is probably that you draw the stroked version on top of the filled one.
Do the inverse and everything will look as you wanted :
var ctx = c.getContext('2d');
ctx.font = "200px Al Tharikh, Arial"
var txt = 'مثال';
ctx.textBaseline = 'top';
// change the stroke style
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;
// first draw the stroke
ctx.strokeText(txt , 100, 0);
// then draw the fill
ctx.fillText(txt , 100, 0);
<canvas id="c" height="200" width="500"></canvas>
Ps : if you want to get only the external stroke, then you can use globalCompositeOperations :
var ctx = c.getContext('2d');
ctx.font = "200px Al Tharikh, Arial"
var txt = 'مثال';
ctx.textBaseline = 'top';
// change the stroke style
ctx.strokeStyle = 'red';
ctx.lineWidth = 5;
// first draw a larger stroke
ctx.strokeText(txt , 100, 0);
// then set the gCO
ctx.globalCompositeOperation = 'destination-out';
// then draw the filled version which will act as an "eraser"
ctx.fillText(txt , 100, 0);
// reset the gCO
ctx.globalCompositeOperation = 'source-over';
canvas{background: ivory;}
<canvas id="c" height="200" width="500"></canvas>
I am trying to draw 2 black lines in HTML5 canvas:
JSFiddle: http://jsfiddle.net/KFNt5/
Javascript:
var canvas = document.createElement('canvas');
canvas.height = 150;
canvas.width = 150;
var canvasContext = canvas.getContext('2d');
canvasContext.beginPath();
// Draw the red line.
canvasContext.strokeStyle = '#000';
canvasContext.moveTo(10, 0);
canvasContext.lineTo(10, 100);
canvasContext.stroke();
// Draw the green line.
canvasContext.moveTo(50, 0);
canvasContext.lineTo(50, 100);
canvasContext.stroke();
document.body.appendChild(canvas);
However, the line to the right is gray, implying that it is semitransparent. How do I ensure that the default opacity is 100 (not transparent at all)?
The second line is lighter due to anti-aliasing. You can include the following line to ensure that you render each line once and avoid the anti-aliasing effect.
canvasContext.translate(0.5, 0.5);
http://jsfiddle.net/bagWQ/
Your first line is darker because you drew it twice, once for each call to stroke(). The second call to stroke() draws both lines because you didn't start a new path.
I want to draw a closed shape(Using paths) & my stroke width is 10.
Now,i want to fill that shape,i can fill it using fill() function of context.
But,when i want to change alpha of my shape,then stroke & fill area overlap at border of shape.
I want only fill the area of shape that remains black after my stroke.
I have attached image of explaining my problem.
Click here to show shape with stork & fill bug.
As you can see in jsfiddle,
-- Color of overlapping area are composite color. That i don't want.
I want it to be exactly same as in border(or stroke color with alpha).
-- i am not enable to specify fill area of closed path.(there is no method of contexx.)
-- I can't use "glabalCompositeOperation",because i am drawing more than 1 shapes in 1 canvas in my application.
The effect you are getting seems to be a property of how canvas draws lines round a shape. Half the thickness of the line is drawn inside the shape and half outside the shape. One way round it is to draw the filled shape and the border as seperate paths. The changes to do this for your example are shown below. This will be more difficult with irregular shapes.
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var topLeftCornerX = 188;
var topLeftCornerY = 50;
var width = 200;
var height = 100;
var linewidth = 10;
context.globalAlpha = 0.5;
context.beginPath();
context.moveTo(topLeftCornerX, topLeftCornerY);
context.lineTo(topLeftCornerX+width,topLeftCornerY);
context.lineTo(topLeftCornerX+width,topLeftCornerY+height);
context.lineTo(topLeftCornerX,topLeftCornerY+height);
context.closePath();
context.fillStyle = "#FF0000";
context.fill();
context.beginPath();
context.moveTo(topLeftCornerX-linewidth/2, topLeftCornerY-linewidth/2);
context.lineTo(topLeftCornerX+width+linewidth/2,topLeftCornerY-linewidth/2);
context.lineTo(topLeftCornerX+width+linewidth/2,topLeftCornerY+height+linewidth/2);
context.lineTo(topLeftCornerX-linewidth/2,topLeftCornerY+height+linewidth/2);
context.closePath();
context.lineWidth = linewidth;
context.strokeStyle = "#00FF00";
context.stroke();
Is it possible to move an image (or image object) without clearing the whole background?
I wish to create an app that allows the user to "paint", using a device that is not the mouse. I would like to have a cursor to follow the users movement with the input device, without having to clear the already painted picture.
Is this possible? And how?
It depends how you handle drawing.
I would suggest using PImage as a canvas to draw into and another PImage to store the pixels of your brush. The 'brush' can be a loaded image, or at the start of your sketch you could make the brush using drawing commands, then store those as a PImage using get().
You will need to clear everything because you want to draw your cursor, but you will also draw your canvas, and you'll store 'brush strokes' only when the mouse is pressed (or some device specific method) by using the copy() or the blend() function (depending on your brush PNG - with or without transparency, etc.)
Here's a quick sketch to illustrate this:
PImage canvas;
PImage brush;
void setup(){
size(800,800);
stroke(128);
smooth();
canvas = createImage(width,height,ARGB);
brush = loadImage("brush.png");
}
void draw(){
background(255);
image(canvas,0,0);
//draw cursor
line(mouseX-5,mouseY-5,mouseX+5,mouseY+5);
line(mouseX+5,mouseY-5,mouseX-5,mouseY+5);
//blend brush pixels into canvas if mouse is pressed
if(mousePressed) canvas.blend(brush, 0, 0, brush.width, brush.width, (int)(mouseX-brush.width*.5), (int)(mouseY-brush.height*.5), brush.width, brush.width,MULTIPLY);
}
Note that you need an image into your sketch's data folder.
You can try it here:
You can run a javascript version bellow:
var canvas;
var brush;
function setup(){
createCanvas(800,800);
stroke(128);strokeWeight(3);
smooth();
canvas = createImage(width,height);
brush = getGradientImg(64,64,random(360),random(100),85);
}
function draw(){
background(255);
image(canvas,0,0);
//draw cursor
line(mouseX-5,mouseY-5,mouseX+5,mouseY+5);
line(mouseX+5,mouseY-5,mouseX-5,mouseY+5);
//blend brush pixels into canvas if mouse is pressed
if(isMousePressed) canvas.blend(brush, 0, 0, brush.width, brush.width, (int)(mouseX-brush.width*.5), (int)(mouseY-brush.height*.5), brush.width, brush.width,MULTIPLY);
//image(brush,mouseX,mouseY);
}
//*
function getGradientImg(w,h,hue,satMax,brightness){
push();//isolate drawing styles such as color Mode
colorMode(HSB,360,100,100);
var gradient = createImage(w,h);//create an image with an alpha channel
var np = w * h;//total number of pixels
var np4 = np*4;
var cx = floor(gradient.width * 0.5);//center on x
var cy = floor(gradient.height * 0.5);//center on y
gradient.loadPixels();
for(var i = 0 ; i < np4; i+=4){//for each pixel
var id4 = floor(i * .25);
var x = id4%gradient.width;//compute x from pixel index
var y = floor(id4/gradient.width);//compute y from pixel index
var d = dist(x,y,cx,cy);//compute distance from centre to current pixel
//map the saturation and transparency based on the distance to centre
gradient.pixels[i] = hue;
gradient.pixels[i+1] = map(d,0,cx,satMax,0);
gradient.pixels[i+2] = brightness;
gradient.pixels[i+3] = map(d,0,cx,255,0);
}
gradient.updatePixels();//finally update all the pixels
pop();
console.log(gradient);
return gradient;
}
//*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>