I have read that you can make an array of anything. In my efforts to go forth in my studies of javaScript/canvas, I set out to create an array of shapes. The idea is to have an array of three circles. Math.floor will be used to grab one element/circle and display it on the canvas. I put together code that, well, makes sense to me... I've created an array, I have filled the array, I am grabbing a random element from the array... I have not yet reached the point of having to display it on the canvas, because not matter my approach, all three circles are always on the canvas. It would be so cool to grasp this concept. Can you tell me why this code doesn't work? Thank you in advance.
<script>
var canvas = document.getElementById("canvas");
var c = canvas.getContext("2d");
var objects = [];
objects[0] =
[c.beginPath(),
c.lineWidth = 5,
c.strokeStyle = 'red',
c.arc(200, 200, 50, 0, Math.PI * 2, false),
c.stroke()];
objects[1] =
[c.beginPath(),
c.lineWidth = 5,
c.strokeStyle = 'dimgray',
c.arc(600, 200, 50, 0, Math.PI * 2, false),
c.stroke()];
objects[2] =
[c.beginPath(),
c.lineWidth = 5,
c.strokeStyle = 'purple',
c.arc(1000, 200, 50, 0, Math.PI * 2, false),
c.stroke()];
for (var i = 0; i < objects.length; i++) {
objects[i] = Math.floor(Math.random() * 3);}
</script>
You should make a function drawCircle which takes a canvas and a color as arguments
const drawCircle = (canvas, color = "red") =>
{
canvas.beginPath ()
canvas.lineWidth = 5
canvas.strokeStyle = color
canvas.arc (95, 50, 40, 0, 2 * Math.PI)
canvas.stroke ()
}
const getCanvas = (id) =>
document.getElementById(id).getContext("2d")
drawCircle (getCanvas('canvas-1')) // default "red"
drawCircle (getCanvas('canvas-2'), 'dimgray')
drawCircle (getCanvas('canvas-3'), 'purple')
<canvas id="canvas-1"></canvas>
<canvas id="canvas-2"></canvas>
<canvas id="canvas-3"></canvas>
We could add additional parameters for position, radius, and line width, but then how would we know which order to pass them in? A better option would be to pass a descriptor object with default values.
const drawCircle = (canvas, descriptor = {}) =>
{
const { x = 95
, y = 50
, radius = 40
, lineWidth = 5
, color = "red"
} = descriptor
canvas.beginPath ()
canvas.lineWidth = lineWidth
canvas.strokeStyle = color
canvas.arc (x, y, radius, 0, 2 * Math.PI)
canvas.stroke ()
}
const getCanvas = (id) =>
document.getElementById(id).getContext("2d")
drawCircle (getCanvas('canvas-1')) // default styles
drawCircle (getCanvas('canvas-2'), { color: 'dimgray' })
drawCircle (getCanvas('canvas-3'), { color: 'purple', radius: 10 })
<canvas id="canvas-1"></canvas>
<canvas id="canvas-2"></canvas>
<canvas id="canvas-3"></canvas>
Above, we use a named parameter descriptor but we could also could've inlined it. Because the descriptor contains so many properties, the readability suffers a bit and makes the previous version of our function a little nicer.
const drawCircle = (canvas, { x=95, y=50, radius=40, lineWidth=5, color="red" } = {}) => {
canvas.beginPath ()
canvas.lineWidth = lineWidth
canvas.strokeStyle = color
canvas.arc (x, y, radius, 0, 2 * Math.PI)
canvas.stroke ()
}
Now, using drawCircle you could create presets, like
const FatPurpleCircle = canvas =>
drawCircle (canvas, { color: "purple", lineWidth: 10 })
const SmallBlueCircle = canvas =>
drawCircle (canvas, { color: "blue", radius: 5 })
And you could have an array of these presets called circles. Given a function sample that returns a random element of an array, we can select a random circle function, and use it to draw its contents on a supplied canvas
const circles =
[ FatPurpleCircle, SmallBlueCircle, ... ]
const sample = (arr = []) => {
const size = arr.length
const rand = Math.floor (Math.random () * size)
return arr[rand]
}
const drawRandomCircle =
sample (circles)
drawRandomCircle (getCanvas('canvas-1'))
One option you have is to store each "canvas" in a function, which are then all stored in an array. This will end up having close to the same format that you had previously, but via a different method. #Patrick Roberts mentioned a similar method in his comment.
var objects = [
function() {
var canvas = document.getElementById("canvas-1");
var c = canvas.getContext("2d");
c.beginPath();
c.lineWidth = 5;
c.strokeStyle = 'red';
c.arc(95,50,40,0,2*Math.PI);
c.stroke();
},
function() {
var canvas = document.getElementById("canvas-2");
var c = canvas.getContext("2d");
c.beginPath();
c.lineWidth = 5;
c.strokeStyle = 'dimgray';
c.arc(95,50,40,0,2*Math.PI);
c.stroke();
},
function() {
var canvas = document.getElementById("canvas-3");
var c = canvas.getContext("2d");
c.beginPath();
c.lineWidth = 5;
c.strokeStyle = 'purple';
c.arc(95,50,40,0,2*Math.PI);
c.stroke();
}
];
objects[0]();
objects[2]();
objects[1]();
Here is a Codepen demonstrating this implementation.
As to why it doesn't work, #Xofox explained it very well in his comment:
[...] you can’t store lines of code in an array. c.arc(600, 200, 50, 0, Math.PI * 2, false) will execute that method, then return undefined. The array stores the result undefined.
Related
I'm currently working on a HTML5 Canvas project (I wrote a separate question about it here). I think one of the solutions to the problems I am facing would be to create a reference for the path (saved as an object), and use the method ispointinpath to check if my mouse position is within the path or not – if its not, it resets the game.
I took a stab at creating a constructor function for a complex path shape. Here's what the complex shape looks like as raw code:
var canvas = document.querySelector('canvas');
// returning a drawing context to a variable 'c'
// allows you to draw 2d elements
var c = canvas.getContext('2d');
canvas.width = 1000;
canvas.height = 700;
canvas.style.width = 1000;
canvas.style.height = 700;
c.beginPath();
c.moveTo(350, 650); //start
c.lineTo(350, 200);
c.lineTo(900, 200);
c.lineTo(900, 250);
c.lineTo(700, 250);
c.lineTo(600, 250);
c.lineTo(600, 650);
c.fillStyle = "#C1EEFF";
c.fill();
<canvas></canvas>
Here's what it looks like as a constructor function that I tried to make:
var canvas = document.querySelector('canvas');
// returning a drawing context to a variable 'c'
// allows you to draw 2d elements
var c = canvas.getContext('2d');
canvas.width = 1000;
canvas.height = 700;
canvas.style.width = 1000;
canvas.style.height = 700;
var points = [(350, 200), (900, 200), (900, 250), (700, 250), (600, 250), (600, 650)];
function Path(startX, startY, array, color){
c.beginPath();
c.moveTo(startX, startY);
// For however many element pairs in the array, create a lineTo statement
for(i = 1; i < array.length; i++){
c.lineTo(array[i][0], array[i][1]);
}
c.fillStyle = color;
c.fill();
}
var blue = new Path(350, 200, points, '#C1EEFF');
<canvas></canvas>
It doesn't seem to be working. Does anyone know why that is? Also, what would be the best syntax for what I'm trying to do?
It would be better if you use an object with position x, y
var canvas = document.querySelector("canvas");
// returning a drawing context to a variable 'c'
// allows you to draw 2d elements
var c = canvas.getContext("2d");
canvas.width = 1000;
canvas.height = 700;
canvas.style.width = 1000;
canvas.style.height = 700;
var points = [
{ x: 350, y: 200 },
{ x: 900, y: 200 },
{ x: 900, y: 250 },
{ x: 700, y: 250 },
{ x: 600, y: 250 },
{ x: 600, y: 650 }
];
function Path(startX, startY, array, color) {
c.beginPath();
c.moveTo(startX, startY);
// For however many element pairs in the array, create a lineTo statement
for (var i = 1; i < array.length; i++) {
c.lineTo(array[i].x, array[i].y);
}
c.fillStyle = color;
c.fill();
}
var blue = new Path(350, 200, points, "#C1EEFF");
<canvas></canvas>
First issue is your points array:
var points = [(350, 200), (900, 200),...
that is not a correct bi-dimensional array, maybe you meant:
var points = [[350, 200], [900, 200],...
also in your code Path is a function not a class, not sure why you doing new Path(...)
maybe you got that mixed with new Path2D() but that is completely different...
Look at the parameters for isPointInPath:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPath#syntax
Here is a working example
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
canvas.width = 1000;
canvas.height = 700;
// Function to generate a Path2D object
function Path(array) {
let path = new Path2D();
path.moveTo(array[0][0], array[0][1]);
for (i = 1; i < array.length; i++) {
path.lineTo(array[i][0], array[i][1]);
}
path.lineTo(array[0][0], array[0][1]);
return path
}
//Create the paths
var big = [[350,200], [900,200], [900,250], [700,250], [600,250], [600,650], [350,650]];
var blue = Path(big);
var triangle = [[25,10], [70,10], [90,85]];
var red = Path(triangle);
// Draw all the paths
c.beginPath()
c.fillStyle = "blue";
c.fill(blue);
c.beginPath()
c.fillStyle = "red";
c.fill(red);
// use isPointInPath
console.log(c.isPointInPath(blue, 10, 10))
console.log(c.isPointInPath(blue, 351,201))
<canvas></canvas>
Now on the now closed question my suggestion to using isPointInPath is to improve scalability, you had a bunch of hard coded if statement, that approach for more complex polygons just would not do... BUT you still have the problem in your game how to handle the transition between levels, that was the root problem on that question.
You seem to be trying to access your array coordinates using this syntax array[i][0], array[i][1] however your array is NOT an array of arrays it is an array of parenthesis. I don’t have time to play with it but try making it an array of arrays so you can then access element [0] and [1].
[[350, 200], [400, 250]] etc
EDIT:
I am providing an ES6 class to create your maps. This is just another option on top of the others provided here.
const canvas = document.querySelector('canvas');
const c = canvas.getContext('2d');
canvas.width = 1000;
canvas.height = 700;
let points = [[300, 400], [400, 400], [400, 350], [400, 250], [700, 250], [700, 150], [750, 150], [750, 50], [775, 50], [775, 175], [725, 175], [725, 400], [500, 400], [500, 500], [500, 650], [300, 650] ];
let points2 = [[750, 50], [775, 50], [775, 100], [750, 100]];
class Map {
constructor(start_x, start_y, arr, c) {
this.start_x = start_x;
this.start_y = start_y;
this.arr = arr;
this.color = c;
}
draw() {
c.beginPath();
c.moveTo(this.start_x, this.start_y); //start
this.arr.forEach(point => c.lineTo(point[0], point[1]));
c.fillStyle = this.color;
c.fill();
c.closePath();
}
}
let map1 = new Map(300, 650, points, 'blue');
let map1Finish = new Map(750, 100, points2, 'red');
map1.draw();
map1Finish.draw();
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="350" height="300"
style="border:6px solid black;">
</canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = 'gold';
ctx.strokeRect(20, 10, 160, 100);
</script>
</body>
</html>
Now, I want to go ahead and turn this drawn rectangle:
ctx.strokeStyle = 'gold';
ctx.strokeRect(20, 10, 160, 100);
Into a variable that I can just simply name "Rectangle" I can easily modify and call it out throughout my project. How can I do that? thank you!
You could use Path2D
Using Path2D to create paths and render them as needed is convenient and from a rendering standpoint paths are a little quicker as the sub paths do not need to be created every time you render the path.
It is best to create the sub paths around the origin (0,0) so you can easily move, rotate and scale them as needed.
Example creating some paths with different content
function createRect() {
const path = new Path2D();
path.rect(-70, -45, 140, 90); // add the sub path;
return path;
}
function createCircle() {
const path = new Path2D();
path.arc(0, 0, 50, 0, Math.PI * 2); // add the sub path;
return path;
}
function createRandLines() {
const path = new Path2D();
var i = 10;
while(i--) {
path.moveTo(Math.random() * 20 - 10, Math.random() * 20 - 10);
path.lineTo(Math.random() * 20 - 10, Math.random() * 20 - 10);
}
return path;
}
To create the paths
const myCircle = createCircle();
const myRect = createCircle();
const myLines1 = createRandLines();
const myLines2 = createRandLines();
You can then render any of the paths with a single function.
function strokePath(path, x, y, lineWidth = ctx.lineWidth, color = ctx.strokeStyle) { // defaults to current style
ctx.setTransform(1, 0, 0, 1, x, y); // position the path so its (0,0) origin is at x,y
ctx.lineWidth = lineWidth;
ctx.strokeStyle = color;
ctx.stroke(path);
}
Passing the path position style and line width to draw the path.
const W = ctx.canvas.width;
const H = ctx.canvas.height;
strokePath(myCircle, Math.random() * W, Math.random() * H);
strokePath(myRect, Math.random() * W, Math.random() * H);
strokePath(myLines1, Math.random() * W, Math.random() * H);
strokePath(myLines2, Math.random() * W, Math.random() * H);
Example
A more detailed draw function and some organisation in regards to the create path functions.
The example creates 4 paths once and then draws them many times, randomly positioned, rotated, scaled, alpha faded, colored, and filled.
const W = canvas.width;
const H = canvas.height;
const ctx = canvas.getContext("2d");
ctx.lineCap = ctx.lineJoin = "round";
// Some math utils
Math.TAU = Math.PI * 2;
Math.rand = (m = 0, M = 1) => Math.random() * (M - m) + m;
Math.randItem = array => array[Math.random() * array.length | 0];
const FACE = [[-3,-38,-34,-32,-47,-16,-48,15,-36,34,-5,43,32,38,47,12,47,-21,25,-35],[-31,-19,-42,-6,-32,1,-9,-6,-6,-24],[5,-24,3,-6,29,2,40,-5,33,-19],[-30,15,-14,32,12,31,29,15,15,15,-2,23,-17,16],[-28,-14,-29,-6,-18,-9,-17,-15],[11,-17,12,-8,20,-6,22,-13,18,-16],[2,-39,0,-53,-9,-60],[-14,17,-16,26,-7,28,-5,22],[2,21,1,28,11,27,13,16]];
// Object to hold path types
const paths = {
rect() {
const path = new Path2D();
path.rect(-20, -10, 40, 20); // add the sub path;
return path;
},
ellipse() {
const path = new Path2D();
path.ellipse(0, 0, 20, 10, 0, 0, Math.TAU); // add the sub path;
return path;
},
randLines() {
const path = new Path2D();
var i = 10;
while (i--) {
path.moveTo(Math.rand(-20, 20), Math.rand(-20, 20));
path.lineTo(Math.rand(-20, 20), Math.rand(-20, 20));
}
return path;
},
face() {
const path = new Path2D();
FACE .forEach(sub => { // each sub path
let i = 0;
path.moveTo(sub[i++] / 3, sub[i++] / 3);
while (i < sub.length) { path.lineTo(sub[i++] / 3, sub[i++] / 3) }
path.closePath();
});
return path;
}
};
// Function to draw scaled, rotated, faded, linewidth, colored path
function strokePath(path, x, y, scale, rotate, alpha, lineWidth, color, fillColor) {
ctx.lineWidth = lineWidth * (1 / scale); //Scale line width by inverse scale to ensure the pixel size is constant
ctx.setTransform(scale, 0, 0, scale, x, y); // position the path so its (0,0) origin is at x,y
ctx.rotate(rotate);
if (fillColor) {
ctx.globalAlpha = 1;
ctx.fillStyle = fillColor;
ctx.fill(path, "evenodd");
}
ctx.globalAlpha = alpha;
ctx.strokeStyle = color;
ctx.stroke(path);
}
// create some paths and colors
const pathArray = [paths.ellipse(), paths.rect(), paths.randLines(), paths.face()];
const colors = "#F00,#FA0,#0B0,#0AF,#00F,#F0A,#000,#888".split(",");
drawRandomPath();
function drawRandomPath() {
strokePath(
Math.randItem(pathArray), // random path
Math.rand(0, W), Math.rand(0, H), // random pos
Math.rand(0.25, 1), // random scale
Math.rand(0, Math.TAU), // random rotate
Math.rand(0.5, 1), // random alpha
1, // constant lineWidth
Math.randItem(colors), // random color
Math.rand() < 0.2 ? "#EED" : undefined, // Fill 1 in 5 with white
);
setTimeout(drawRandomPath, 250); // draw another path every quarter second.
}
* {margin:0px}
canvas {border:1px solid}
<canvas id="canvas" width="600" height="190"></canvas>
You can not do that with current standards unfortunately, you will have to redraw the shape, you can do something like:
var shape = x:10,y:20,width:20,height:40
clear the canvas and redraw with created variable:
shape.width = 100;
ctx.rect(shape.x,shape.y,shape.width,shape.height);
My question is: how should I do the logical and mathematical part, in order to calculate the position of each arc, when an event is emitted: "click", "mouseover", etc.
Points to consider:
. Line width
. They are rounded lines.
. Arc length in percentage.
. Which element is first, ej: z-index position.
My source code
Thank you for your time.
There is a convenient isPointInStroke() method, just for that.
To take the z-index into consideration, just check in the reverse order you drew:
const ctx = canvas.getContext('2d');
const centerX = canvas.width/2;
const centerY = canvas.height/2;
const rad = Math.min(centerX, centerY) * 0.75;
const pathes = [
{
a: Math.PI/4,
color: 'white'
},
{
a: Math.PI/1.5,
color: 'cyan'
},
{
a: Math.PI,
color: 'violet'
},
{
a: Math.PI*2,
color: 'gray'
}
];
pathes.forEach(obj => {
const p = new Path2D();
p.arc(centerX, centerY, rad, -Math.PI/2, obj.a-Math.PI/2);
obj.path = p;
});
ctx.lineWidth = 12;
ctx.lineCap = 'round';
function draw() {
ctx.clearRect(0,0,canvas.width,canvas.height);
// since we sorted first => higher z-index
for(let i = pathes.length-1; i>=0; i--) {
let p = pathes[i];
ctx.strokeStyle = p.hovered ? 'green' : p.color;
ctx.stroke(p.path);
};
}
function checkHovering(evt) {
const rect = canvas.getBoundingClientRect();
const x = evt.clientX - rect.left;
const y = evt.clientY - rect.top;
let found = false;
pathes.forEach(obj => {
if(found) {
obj.hovered = false;
}
else {
found = obj.hovered = ctx.isPointInStroke(obj.path, x, y);
}
});
draw();
}
draw();
canvas.onmousemove = canvas.onclick = checkHovering;
canvas{background: lightgray}
<canvas id="canvas"></canvas>
And if you need IE support, this polyfill should do.
It's much better to "remember" the objects you drew, rather than drawing them and trying to gather what they are from what you drew. So, for example, you could store the render information: (I don't know typescript)
let curves = [{start: 30, length: 40, color: "white"}/*...*/];
Then, render it:
ctx.fillStyle = curve.color;
ctx.arc(CENTER_X, CENTER_Y, RADIUS, percentToRadians(curve.start), percentToRadians(curve.start + curve.length));
Then, to retrieve the information, simply reference curves. The z values depend on the order of the render queue (curves).
Of course, you probably could gather that data from the canvas, but I wouldn't recommend it.
I am plotting a bar chart with some series values in a javascript loop. Even though the code drawing the series values lies below the code that draws the bars, in the next iteration of the loop the text that has just been drawn gets overwritten.
You can see this effect taking place in the code below as the alert boxes appear.
Why do drawing operations on another part of the canvas overwrite something drawn previously in a completely different place?
Update: Someone has helpfully pointed out that using fillRect() hides this issue, but my question is rather: why is it happening in the first place?
var exampleData = {
"Series 1": 10,
"Series 2": 14,
"Series 3": 2,
"Series 4": 12
};
var BarChart = function(options) {
this.options = options;
this.canvas = options.canvas;
this.ctx = this.canvas.getContext("2d");
this.colors = options.colors;
this.plot = function() {
var maxValue = 0;
for (var categ in this.options.data) {
maxValue = Math.max(maxValue, this.options.data[categ]);
}
var noBars = Object.keys(this.options.data).length;
var barWidth = (this.canvas.height) / noBars;
var barIdx = 0;
for (categ in this.options.data) {
var barLength = Math.round(this.canvas.width * this.options.data[categ] / maxValue);
this.ctx.save();
alert("plotting series line " + categ);
this.ctx.fillStyle = this.colors[barIdx % this.colors.length];
this.ctx.rect(30, barIdx * barWidth, barLength, barWidth);
this.ctx.fill();
alert("plotting series value " + categ);
this.ctx.fillStyle = "#000000";
this.ctx.font = "24px Georgia";
this.ctx.textBaseline = "middle";
this.ctx.fillText(this.options.data[categ], 25, barIdx * barWidth + barWidth / 2); //will be covered in the loop's next iteration. Why?
this.ctx.restore();
barIdx++;
}
}
}
function init() {
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = 800;
myCanvas.height = 300;
var ctx = myCanvas.getContext("2d");
var myBarChart = new BarChart({
canvas: myCanvas,
seriesName: "Example Series",
padding: 40,
data: exampleData,
colors: ["#D1E3F3", "#D1E3F3", "#D1E3F3", "#D1E3F3"]
});
myBarChart.plot();
}
document.addEventListener("DOMContentLoaded", init, false);
<canvas id="myCanvas"></canvas>
Changing :
this.ctx.rect(30, barIdx * barWidth, barLength, barWidth);
this.ctx.fill();
To instead use fillRect() fixes the problem:
this.ctx.fillRect(30, barIdx * barWidth, barLength, barWidth);
Working example here (compared to the original example here)
how can I fill the "new" canvas circle that appears next to the older one.
There is no problem with rectangle for example:
**
ctx.fillStyle = 'rgba('+quadratto.r+','+quadratto.g+','+quadratto.b+',1)';
quadratto.x += quadratto.speedX;
quadratto.y += quadratto.speedY;
quadratto.speedY += quadratto.speedY*(-0.15);
ctx.fillRect(quadratto.x-quadratto.h/4, quadratto.y-quadratto.h/2, 2, 2);**
What I want to do?
I'm creating animation in canvas where random-sized-color circle will appear and
it will move in a specified direction. The new canvas layaer will appear in the next frame (fps) with a new(old) circle.
var myCanvasPattern = document.createElement('canvas');
myCanvasPattern.width = window.innerWidth;
myCanvasPattern.height = window.innerHeight;
document.body.appendChild(myCanvasPattern);
var ryC = myCanvasPattern.getContext('2d');
function lottery(min, max) {
return Math.floor(Math.random()*(max-min+1))+min;
}
var allQuadro = [];
var fps = 50;
var lastTime = 0;
animationLoop();
function animationLoop(time){
requestAnimationFrame( animationLoop );
if(time-lastTime>=1000/fps){
lastTime = time;
for(var i=0;i<10;i++){
allQuadro.push({
r : lottery(0, 240),
g : lottery(0, 240),
b : lottery(0, 240),
circleR : lottery(10, 30),
x : myCanvasPattern.width/2,
y : myCanvasPattern.height/2,
speedX : lottery(-1000,1000)/100,
speedY : lottery(-1000,1000)/100
})
}
ryC.fillStyle = 'rgba(255,255,255,0.2)';
ryC.fill(0,0,myCanvasPattern.width, myCanvasPattern.height);
for(var i=0; i<allQuadro.length;i++){
var circle = allQuadro[i];
ryC.fillStyle = 'rgba('+circle.r+','+circle.g+','+circle.b+',1)';
circle.x += circle.speedX;
circle.y += circle.speedY;
//HERE's THE PROBLEM BELOW. HOW TO CREATE NEW ONE THAT APPEARS NEXT TO PREVIOUS ONE WITH NEW RANDOM COLOR
ryC.arc(circle.x-circle.circleR/2, circle.y-circle.circleR/2, circleR, 0, 2 * Math.PI);
//ryC.fill();
}
// ryC.fillStyle = 'rgba('+r+','+g+','+b+',1)';
//ryC.arc(x+speedX, y+speedY, circleR, 0, 2 * Math.PI);
//ryC.fill();
}
}
body {
margin: 0;
padding: 0;
overflow: hidden;
}
The fillRect() will fill directly to the canvas without going via a path (versus for example rect()).
The arc() on the other hand will add to a path which needs to be filled later. It also require the path to be cleared in-between the calls using beginPath().
A simple way to think about it is to wrap the necessary code into a function that acts like fillRect():
function fillArc() {
ctx.beginPath(); // clear current path
ctx.arc.apply(ctx, arguments); // apply arguments to arc() call
ctx.fill();
// notice that the arc still exist on the path after this call
// so to "truly" behave like fillRect() you could consider an
// additional beginPath() here.. it will depend on your code
}
In action:
var ctx = c.getContext("2d");
ctx.fillStyle = "#09f";
fillArc(70, 70, 70, 0, 6.28);
ctx.fillStyle = "#0a9";
fillArc(220, 70, 70, 0, 6.28);
function fillArc() {
ctx.beginPath();
ctx.arc.apply(ctx, arguments);
ctx.fill();
}
<canvas id=c></canvas>
If you are bold you can also add the method to the context itself before calling getContext():
CanvasRenderingContext2D.prototype.fillArc = function() {
this.beginPath();
this.arc.apply(this, arguments);
this.fill();
}
The use it like any other method:
ctx.fillArc( ... );
CanvasRenderingContext2D.prototype.fillArc = function() {
this.beginPath();
this.arc.apply(this, arguments);
this.fill();
}
var ctx = c.getContext("2d");
ctx.fillStyle = "#09f";
ctx.fillArc(70, 70, 70, 0, 6.28);
ctx.fillStyle = "#0a9";
ctx.fillArc(220, 70, 70, 0, 6.28);
<canvas id=c></canvas>