I need split circle to X parts without white center
I have already this code: http://jsfiddle.net/U2tPJ/78/
I get this result:
I need finish result like this (without white center):
Since what you want is to fill a part of the circle, use fill(), not stroke().
• The shape you want to draw (a pie) starts in the circle center :
ctx.moveTo(x,y);
Then follow the arc :
context.arc(x, y, radius, i*pieAngle, (i+1)*pieAngle, false);
Then fill().
• Notice that the segmentDepth you were using was in fact an angle in degree. To clarify i used :
// size of a pie : it is an angle in radians
var pieAngle = 2 * Math.PI / hours;
• Lastly i used hsl colors to easily get a bunch of colors different for each hour :
var hueValue = i * 15;
context.fillStyle = 'hsl(' + hueValue + ',70%, 60%)';
result look this way :
draw code
function drawSegments(radius) {
for (var i = 0; i < hours; i++) {
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, i*pieAngle, (i+1)*pieAngle, false);
context.lineWidth = segmentDepth;
var hueValue = i * 15;
context.fillStyle = 'hsl(' + hueValue + ',70%, 60%)';
// '#'+(Math.random()*0xFFFFFF<<0).toString(16);
context.fill();
context.lineWidth = 2;
context.strokeStyle = '#444';
context.stroke();
}
}
fiddle : http://jsfiddle.net/gamealchemist/U2tPJ/79/
The width of the ring is controlled by the line context.lineWidth = segmentDepth;. It seems like you forgot that the line width goes into both directions. To make the ring go to the center, change it to segmentDepth * 2. However, this will also make the whole graphic twice as big, so you might want to compensate by reducing the segmentDepth.
Related
I have a triangle in canvas and I want to fill it with color .. maybe more than one color .. how I can do that ?
my triangle is here :
function draw() {
var width = 360; // Triangle Width
var height = 400; // Triangle Height
var padding = 90;
// Draw a path
ctx.beginPath();
ctx.moveTo(padding + width/2, padding+height); // Top Corner
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.closePath();
ctx.strokeStyle = "#e8ecef";
ctx.lineWidth = 25;
ctx.stroke();
ctx.restore();
}
the current result is like the one in this image :
the result I want something like this :
please any help ? how I can do this ? or if there is any plugin will help me to do this faster ?
Composition modes
The problem can be solved simply by using a couple of composition modes and very little math (only to calculate correct position).
The receipt would be:
Draw a mask representing the full triangle background (color does not matter as long as it is opaque)
Create a gradient with hard transitions to define different color sections.
Composite a rectangle on top which is clipped to background shape using source-in mode.
Stroke the border using the normal source-over mode
All these steps can reuse a single path. The gradient will allow you to define all colored sections in one place. Just make sure each section starts and end with the same color and that the next section will start from where the previous stopped. This will make a hard edge between the sections.
Since the gradient color stops takes normalized values, it becomes a simple task to match any size simply by defining the gradient line's start and stop points relative to the triangle's position and size.
Adjust as needed.
Example with modified code
I inserted the code in your base code to show where the modifications needs to be.
var ctx = c.getContext("2d"),
width = 360, height = 400, padding = 90, split = 0.33;
// Draw a path that will be reused below
ctx.beginPath();
ctx.moveTo(padding + width/2, padding+height); // Top Corner
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.closePath();
// fill for a mask (color doesn't matter as long as it's opaque)
ctx.fill();
// define gradient
var gr = ctx.createLinearGradient(0, padding, 0, padding+height); // line
gr.addColorStop(0 , "rgb(187, 19, 221)");
gr.addColorStop(split, "rgb(187, 19, 221)");
gr.addColorStop(split, "rgb(38, 199, 222)");
gr.addColorStop(1 , "rgb(38, 199, 222)");
// fill the colored sections (adjust positions as needed)
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = gr;
ctx.fillRect(0, 0, c.width, c.height);
// stroke outline
ctx.globalCompositeOperation = "source-over";
ctx.strokeStyle = "#e8ecef";
ctx.lineWidth = 25;
ctx.stroke();
<canvas id=c width=500 height=550></canvas>
Effectively, a good way to do this is to draw a base triangle and then a trapezium over the top of this, and then do the stroke over these.
function draw(percent) {
var width = 360; // Triangle Width
var height = 400; // Triangle Height
var padding = 90;
// Draw the purple triangle underneath
ctx.beginPath();
ctx.moveTo(padding + width/2, padding+height); // Top Corner
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.fillStyle = "#990099";
ctx.fill();
// Draw second triangle/trapezium over the top
ctx.beginPath();
ctx.moveTo(padding + width*percent/2, padding+height*percent); //Bottom left
ctx.lineTo(padding + width - width*percent/2, padding+height*percent); //Bottom right
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.fillStyle = "#00ccff";
ctx.fill();
// Draw the grey line around the triangles
ctx.beginPath();
ctx.moveTo(padding + width/2, padding+height); // Top Corner
ctx.lineTo(padding + width, padding); // TOP Right
ctx.lineTo(padding, padding); // TOP Left
ctx.closePath();
ctx.strokeStyle = "#e8ecef";
ctx.lineWidth = 25;
ctx.stroke();
ctx.restore();
}
draw(0.1);
The draw function works with any value between 0 and 1, where 0 is 0% blue and 1 is 100% blue. As this is a triangle, the area filled will not appear equal if at 50%, however the percentage will be halfway between the top and bottom coordinates.
I hope this helps
Triangles and area
To solve for fraction (p) (0-1) to give new height (h1) for a triangle (w) width and (h) height
Area of triangle is
w * h * 0.5
Cutting the triangle will give a triangle and a trapezoid.
We will solve so that the fraction area is the area of the trapezoid.
The area of a trapezoid (the other end to the pointy end) in terms of the triangle w,h and h1 where h1 is the unknown height of the trapezoid.
a1 = w * h1 - (w / 2 * h) * h1 * h1
The h1 * h1 means this solution will be a quadratic so make a formula that equates to 0. We know the area of the trapezoid is the triangle area times the fraction, so use that (w * h * 0.5 * p) and subtract the above area solution in terms of h1 to give
0 = w * h * 0.5 * p - w * h1 - (w / 2 * h) * h12
This gives a quadratic the general form is ax2 + bx + c = 0 (in this case the unknown value x is h1 the height of the trapezoid) which can be solved with (-b (+/-) sqrt(b2 - 4ac) ) / 2a. Because of the (+/-) in the solution there are two answers, at this stage it is unknown which answer is correct.
thus to solve we need a,b,c which are
a = w/(2*h)
b = - w
c = w * h * 0.5 * p
So as a function
// return the height of the trapezoid made from a triangle of width height that
// has an area equal to the area of the triangle * fraction
function getFractionHeightOfTriangle(width,height,fraction){
var a = width / (2 * height);
var b = -width;
var c = width * height * 0.5 * fraction;
// find the two solutions
var h1_a = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
var h1_b = (-b - Math.sqrt(b * b - 4 * a * c)) / (2 * a);
// from experiment the solution is the second one
// or you can check which is positive and return that
return h1_b;
}
To draw a triangle using the top as the origin
// x,y is the top (pointy end) w is width h is height
// col is stroke colour, col1 is fillColour
// lineW is line width.
var drawTriangle = function(x,y,w,h,col,col1,lineW){
ctx.beginPath();
ctx.strokeStyle = col;
ctx.fillStyle = col1;
ctx.lineWidth = lineW;
ctx.moveTo(x,y );
ctx.lineTo(x + w / 2 ,y + h);
ctx.lineTo(x - w / 2 ,y + h);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
To draw part of a triangle
// See above function for x,y,w,h,col,col1,lineW
// which is == "top" for pointy end and != "top" for trapezoid
// amount is the height of the top
var drawPartTriangle = function(x,y,w,h,which,amount,col,col1,lineW){
ctx.beginPath();
ctx.strokeStyle = col;
ctx.fillStyle = col1;
ctx.lineWidth = lineW;
if(which === "top"){
ctx.moveTo(x,y);
ctx.lineTo(x + w / 2 * (amount / h),y + amount);
ctx.lineTo(x - w / 2 * (amount / h),y + amount);
}else{
ctx.moveTo(x + w / 2 * (amount / h),y + amount);
ctx.lineTo(x + w / 2 ,y + h);
ctx.lineTo(x - w / 2 ,y + h);
ctx.lineTo(x - w / 2 * (amount / h),y + amount);
}
ctx.closePath();
ctx.fill();
ctx.stroke();
}
I am able to draw these letters using a path. But what I want to do is use that path and fill in what the red image shows instead of filling in the letters.
Here is the code I am using:
function mattes_draw_letter(x, y, width, height, letter, position)
{
var canvas = document.createElement('canvas');
canvas.style.position = "absolute";
canvas.style.top = y + "px";
canvas.id = "canvas_opening_" + position;
canvas.style.zIndex = 5;
canvas.width = width;
canvas.height = height;
canvas.style.left = x + "px";
var ctx = canvas.getContext("2d");
ctx.lineWidth = 1;
ctx.fillStyle = '#bfbfbf';
ctx.strokeStyle = '#000000';
ctx.beginPath();
ctx.moveTo(letter[0] * width, letter[1] * height);
for (i = 0; i < letter.length; i+=2)
{
if (typeof letter[i+3] !== 'undefined')
{
ctx.lineTo(letter[i+2] * width, letter[i+3] * height);
}
}
ctx.fill();
ctx.stroke();
ctx.closePath();
$("#mattes").append(canvas);
canvas.addEventListener("drop", function(event) {drop(event, this);}, false);
canvas.addEventListener("dragover", function(event) {allowDrop(event);}, false);
canvas.addEventListener("click", function() {photos_add_selected_fid(this);}, false);
}
This is what I currently have:
This is what I would like:
Just fill the boxes with red color before drawing the letters in gray.
I was able to do this by adding two lines of code in your code.
ctx.fillStyle = "#F00";
ctx.fillRect(0, 0, width, height);
Put these two lines between the lines:
ctx.lineWidth = 1;
and
ctx.fillStyle = '#bfbfbf';
I assume you're starting the existing letters otherwise (as #Chirag64 says), you can just draw the red rectangles first and then draw the letters on top).
You can use canvas compositing to "draw behind" existing content.
A Demo: http://jsfiddle.net/m1erickson/695dY/
In particular the destination-over compositing mode will draw new content behind existing content (new content is only drawn where the existing content is transparent).
context.globalCompositeOperation="destination-over";
Assuming the HOPE characters are drawn over a transparent background you can add red rectangles behind the HOPE characters like this:
// draw red rectangles **behind** the letters using compositing
ctx.fillStyle="red";
ctx.globalCompositeOperation="destination-over";
for(var i=0;i<4;i++){
ctx.fillRect(i*62+16,13,50,88); // your x,y,width,height depend on your artwork
}
function TrackGraphic(model, canvas) {
//TrackModel
this._model = model;
this.draw = function(context) {
var dx = Math.cos(this._model.startAngle + Math.PI / 2);
var dy = Math.sin(this._model.startAngle + Math.PI / 2);
context.beginPath();
context.lineWidth = 10;
context.moveTo(this._model.offsetX, this._model.offsetY);
//CurvePoint
var p;
for (var d = 0; d < this._model.length; d += 1) {
if (d > 1000) {
console.log('2F2F2F');
context.strokeStyle = "#2F2F2F" //"rgb(255,165,0)"; //0x2F2F2F
} else {
context.strokeStyle = "#FFF" //"rgb(255,165,0)"; //0x2F2F2F;
console.log('FFFFFF');
}
p = this._model.getTrackPoint(d);
context.lineTo(this._model.offsetX + p.x, this._model.offsetY + p.y)
}
context.stroke();
}
}
The above code produces the lines in the canvas. The line is one color, I want to at the beginning or in any municipal color was different. My code does not work: (why?. How to fix it?
Changing the color while you are constructing the path doesn't do anything. The color is applied only once, when stroke() is called, so the last strokeStyle you set will be the color of the entire line.
beginPath(), moveTo(), lineTo(), etc only create a path and that path itself has no color. Stroking or filling that path only ever apply a single color.
If you want a path that is multiple colors you will have to do one of two things:
Begin a path, do some number of lines, stroke it one color, and then begin another path that will be stroked with a different color. In other words:
// make a red line segment
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x, y);
ctx.strokeStyle = 'red';
ctx.stroke();
// Begin a new path and make this line segment green
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x, y);
ctx.strokeStyle = 'green';
ctx.stroke();
//etc
Or, depending on what you're doing you could also use a linearGradient
Here is my pseudo code:
var percentage = 0.781743; // no specific length
var degrees = percentage * 360.0;
var radians = degrees * Math.PI / 180.0;
var x = 50;
var y = 50;
var r = 30;
var s = 1.5 * Math.PI;
var context = canvas.getContext('2d');
context.beginPath();
context.lineWidth = 5;
context.arc(x, y, r, s, radians, false);
context.closePath();
context.stroke();
I'm using the KineticJS library to control the shapes I make and redraw them as necessary. My problem is that the above code does not work at all. I assume I have the math incorrect, because if I change radians to something like 4.0 * Math.PI is draws the entire circle.
I've been using HTML5 Canvas Arc Tutorial for reference.
Your code works just fine, but you have a starting angle that ought to be zero to get what you expect. Here's working code:
http://jsfiddle.net/HETvZ/
I think your confusion is from what starting angle does. It does not mean that it starts at that point and then adds endAngle radians to it. It means that the angle starts at that point and ends at the endAngle radians point absolutely.
So if you startAngle was 1.0 and endAngle was 1.3, you'd only see an arc of 0.3 radians.
If you want it to work the way you're thinking, you're going to have add the startAngle to your endAngle:
context.arc(x, y, r, s, radians+s, false);
Like in this example: http://jsfiddle.net/HETvZ/5/
Your code is just fine. you need to have:
s=0 i.e. starting point must be zero.
and if you want circle to start drawing at top you can use:
context.rotate(-90 * Math.PI / 180);
but after rotating you will have to check arc()'s x,y arguments. i used it like:
context.rotate(-90 * Math.PI / 180);
context.arc(-200, 200, 150, startPoint, radian, false);
context.lineWidth = 20;
context.strokeStyle = '#b3e5fc';
context.stroke();
context.closePath();
after this i needed to display percentage in text form so i did:
context.rotate(90 * Math.PI / 180);
context.fillStyle = '#1aa8ff';
context.textAlign = 'center';
context.font = "bold 76px Verdana";;
context.textBaseline = "middle";
context.fillText("50%", 200, 200);
trying to divide a semicircular region into colored segments in HTML Canvas.
Here's what I tried,
ctx.save();
ctx.translate(c.width / 2, (c.height / 2)-1);
ctx.strokeStyle = "red"
ctx.lineWidth = 3;
ctx.lineCap = "round";
var x=400; // number of times lineTo strokes. Greater the value the better is the smoothness
var factor=1; //with =1, the entire semicirular region is filled.
for (var i = 0; i < x; i++) {
//ctx.rotate(Math.PI);
ctx.beginPath();
ctx.strokeStyle = "rgba(255,0,0,1)";
//ctx.rotate(-Math.PI/2);
ctx.rotate((-Math.PI * factor) / x);
//1st color segment, factor=1 helps to paint 100% of semicircular region
ctx.moveTo(122, 0);
ctx.lineTo(70, 0);
ctx.stroke();
//ctx.rotate(Math.PI); //2nd color segment
Alternate way, might be to use concentric arc() segments. I'm trying that now. But any one who can throw some light would be a great help.
the sample at http://www.phpied.com/wp-content/uploads/2008/02/canvas-pie.html was the one I was looking for.
Uses concentric arc() as I anticipated.