I was trying out a simple script to create a rectangle and it seemed to work find except that the final leg of the polygon doesn't connect with the first leg properly. The strange thing is that all the other legs do connect properly.
Before anyone suggests that I use the built-in drawRect() or similar function, I should emphasize that this is just a simple example of a far more complex figure I'm trying to draw. I'm just confused why this is happening.
newX = 10;
letterHeight = 100;
ctx.strokeStyle = "#999999";
ctx.lineWidth = 6;
ctx.moveTo(newX,letterHeight*0.5);
ctx.lineTo(newX+letterWidth,letterHeight*0.5);
ctx.lineTo(newX+letterWidth,letterHeight);
ctx.lineTo(newX, letterHeight);
ctx.lineTo(newX, letterHeight*0.5);
ctx.stroke();
It seems to me that this probably has something to do with the line width and I could consider some problem-specific crude fix for that but is there a more general fix if that's the case?
Link to how the script rendered (using firefox)
Use ctx.closePath(); just before the stroke command to close the path. You should also be starting the path with ctx.beginPath();
Related
With the help of D3js i am generating splines from a set of points on a 2D canvas in HTML and JavaScript.
private spline = d3.line()
.x(p => p.x)
.y(p => p.y)
.curve(d3.curveBundle.beta(1));
This is added to a canvas with some native JS code:
ctx = [HTMLCanvasElement].getContext('2d'); // pseudo-code
ctx.beginPath();
this.spline(points);
ctx.stroke();
ctx.closePath();
This works fine in case I am rendering one path at a time. As soon as I am having multiple pathes with the same starting point, they are starting to overlap. And this causes some unwanted rendering effects: These paths are getting edgy and jaggy.
I've already tried to increae the context.imageSmoothingQuality = 'high' and played around with ctx.globalCompositeOperation without any help.
A possible solution would be IMHO to removed that overlapping part and "glue" the pathes from that point, when they are splitting. The redundant part would be removed and the side effects would be vanished, but this sounds like a hard programming story to figure out reliably where the splines begin.
Important note: These splines or pathes are rendered randomly. Only the starting and ending points are fixed. If you like, have a look at: http://b612-webdesign.de/kardion/guilloche/ (Hit "Aktualisieren" to generate a new graph)
„Minimal“ reproducable example: https://observablehq.com/#nextlevelshit/d3js-canvas-splines
You'll find at ObservableHQ an example of my issue. You can change the code and re-run the rendering at anytime.
I'm using HTML5 Canvas elements in a project I'm working on and while rendering a bunch of stuff I ran into a really strange artifact that I'm wondering if anyone has ever seen before. Basically, in this particular scenario (this is the only case I've seen that produces this behavior), I happened to be panning/zooming in my application and noticed a very bizarre rendering effect on part of the canvas. Upon further inspection, I was able to reproduce the effect in a very simplistic example:
In this case, I have a path (whose coordinates don't change) and all that is changing from the first screenshot to the second is the applied transformation matrix (by a very small amount).
You can access the JSFiddle I used to generate these screenshots at https://jsfiddle.net/ynsv66g8/ and here is the relevant rendering code:
// Clear context
context.setTransform(1, 0, 0, 1, 0, 0);
context.fillStyle = "#000000";
context.fillRect(0, 0, 500, 500);
if (showArtifact) { // This transformation causes the artifact
context.transform(0.42494658722537976, 0, 0, -0.42494658722537976, 243.95776291868646, 373.14630356628857);
} else { // This transformation does not
context.transform(0.4175650109545749, 0, 0, -0.4175650109545749, 243.70987992043368, 371.06797574381795);
}
// Draw path
context.lineWidth = 3.488963446543301;
context.strokeStyle = 'red';
context.beginPath();
var p = path[0];
context.moveTo(p[0], p[1]);
for (var i = 1; i < path.length; ++i) {
p = path[i];
context.lineTo(p[0], p[1]);
}
context.closePath();
context.stroke();
It looks to be related to the call to canvas.closePath() because if you remove the call to context.closePath() and replace it with:
p = path[0];
context.lineTo(p[0], p[1]);
(thus manually "closing" the path) everything works properly (granted, this really doesn't fix my particular issue because I rely on multiple closed paths to apply filling rules).
Another interesting change that can be made that makes the issue go away is to reverse the path array (i.e., by adding a call to path.reverse() right after its definition).
Together, all of this seems to be adding up to some kind of browser rendering bug related to the characteristics of the path, especially since, on my Mac, the issue occurs in both Chrome (v61.0.3163.91) and Firefox (v55.0.3) but not Safari (v11). I've done some extensive searching to try to find this issue (or something similar), but thus far have come up empty.
Any insight into what might be causing this (or the proper way to go about reporting this issue if the consensus is that it is caused by some browser bug) would be greatly appreciated.
it seems a line mitering problem; that is, the renderer fails to correctly join lines when the width is too big relative to the segment size/orientation.
This seems not influenced by path closing ( I can reproduce the artifact with the open path ); note that manually closing the path is not the same as a closePath(), because no line join is performed in the former case.
As far as I can tell, it seems solved by setting lineJoin to 'round' or reducing the line width ... anyway, seems a renderer bug to me ... just my two cents :)
Good evening, first i'm not sure i should post this here, since i have litteraly no idea what's wrong here (only clue is it happened after i moved all my variables at the top of my code while trying to "clean up" a little).
but here is the problem: i've created a canvas game and after moving my variables (i think) i started getting major framedrops. Game weighs less than 20Ko, images are super tiny and simple, i have a for loop in the update loop but it never seemed to be a problem (it's not infinite) so in short i do not know what's wrong here
here is a bit of code since links to code "must be accompanied by code" (dont know what's up with that)
for (var i = 0; i<boxes.length; i++){
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var col = coli(player,boxes[i])
};
i've tried different things, like disabling functions (anim and colision), friction and gravity but nothing seems to have any effect, and i dont know that much about the dom except how to look at my own variables so i havent found anything with firebug.
Really hope someone has an idea
You need to add ctx.beginPath() before using ctx.rect, moveTo, lineTo, arc, and any function you need to use ctx.stroke() or ctx.fill() to see.
beginPath tell the canvas 2D context that you wish to start a new shape. If you do not do this you end up adding more and more shapes each update.
From your fiddle
function update() {
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = pat;
//===============================================================
ctx.beginPath() // <=== this will fix your problem. It removes all the
// previous rects
//===============================================================
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
// or use ctx.fillRect(...
var col = coli(player, boxes[i])
};
ctx.fill();
I have problem with javascript canvas.
I'm trying to put on canvas several object which are moving and bouncing on edges of canvas. If i create one object, there is no problem with it, but if i want to create more objects, they become connected.
Fiddle example:
https://jsfiddle.net/mwbgwa39/
I will be very thankfull if someone could help me :)
Important thing is to call beginPath() at the begining of each object drawing and closePath() when you are done drawing that object. If you don't call it canvas thinks that you are trying to continue drawing last object. You can read more on MDN
for(i in obj_t)
{
ctx.beginPath();
obj_t[i].xPos = obj_t[i].xPos + obj_t[i].xVel;
obj_t[i].yPos = obj_t[i].yPos + obj_t[i].yVel;
ctx.arc(obj_t[i].xPos, obj_t[i].yPos, obj_t[i].r, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
ctx.closePath(); // optional
}
EDIT: As Kaiido noticed calling closePath() in this example is not necessary. More info on when you should call closePath() can be found in this SO question.
You're drawing a path. Each time you draw something it continues the path you have made so far. You can move beginPath into the for loop to start a new path for each circle:
ctx.clearRect(0, 0, 400, 400);
for(i in obj_t)
{
ctx.beginPath();
// draw here
}
ctx.closePath();
See in action: https://jsfiddle.net/mwbgwa39/4/
Are there any open source libraries (JaveScript) that implement even-odd fill rule on canvas.
If I try to implement it myself then how complex would it be (considering general case which has complex curves also) and would it hit on the performance (due to overhead of doing it for each pixel in JaveScript).
What are the methods for converting even-odd fill to non-zero winding (considering a generic solution that will work for every case). Once method I found was to divide the shape into all non-intersecting polygons and fill them separately.
One option is to use SVG and draw the SVG on canvas, but I also found that native SVG rendering is a bit slow on iPad, but is SVG slow even when I draw it on HTML canvas (on iPad)?
Thanks in advance
I came across this question as I was looking for the same some time ago. That is, use a "evenodd" fill-rule inside a HTML canvas.
After a little research, and going through mailing lists and patches, I noticed that, as it turns out, recent versions of both Firefox and Chrome have support for this, but each in a different, browser-specific, way.
In Firefox it is a matter of using the mozFillRule attribute. Example:
//
// Firefox Example
//
// canv has the HTML canvas element
var ctx = canv.getContext("2d");
ctx.fillStyle = "#ff0000";
ctx.mozFillRule = 'evenodd';
ctx.beginPath();
ctx.moveTo(100, 10);
ctx.lineTo(40, 180);
ctx.lineTo(190, 60);
ctx.lineTo(10,60);
ctx.lineTo(160,180);
ctx.closePath();
ctx.fill();
In Chrome, you do it by passing the string evenodd as a parameter to the fill method. Example:
//
// Chrome Example
//
// canv has the HTML canvas element
var ctx = canv.getContext("2d");
ctx.fillStyle = "#ff0000";
ctx.beginPath();
ctx.moveTo(100, 10);
ctx.lineTo(40, 180);
ctx.lineTo(190, 60);
ctx.lineTo(10,60);
ctx.lineTo(160,180);
ctx.closePath();
ctx.fill('evenodd');
These are the two browsers I researched for, so I don't know about the state of this in other browers. Hopefully in the not-so-distant future we will be able to use this feature via the fillRule attibute that is now part of the HTML standard.
See fill() method API:
void ctx.fill();
void ctx.fill(fillRule);
void ctx.fill(path, fillRule);
fillRule can be "nonzero" or "evenodd"
--- "nonzero": The non-zero winding rule, which is the default rule.
--- "evenodd": The even-odd winding rule.
Browser compatibility:
--- IE 11+, Firefox 31+, Chrome are OK.
--- I didn't test on IE 9/10.
--- Use ctx.mozFillRule = 'evenodd'; with old Firefox 30/30-.