Why is canvas blurry? [duplicate] - javascript

I'm trying to draw a grid of white lines on a black background.
The bottom 3 horizontal lines seem faded until I redraw them, and I can't figure out why this is happening. Has anyone seen this before and/or know what I'm doing wrong?

This is due to the fact lines are drawn over all pixels they're over (on canvas positionning is in float). When you want to draw precise vertical or horizontal lines in javascript on a canvas, you'd better have them in half ints.
See illustration : The first horizontal line was drawn with a y position of 1. This line is fuzzy and wide. The second horizontal line was drawn with a y position of 4.5. It is thin and precise.
For example in your code, I had good results by changing your horizontal lines loop to this :
// Horizontal lines
for (var i = 1; i < objCanvas.height / intGridWidth; i++)
{
objContext.strokeStyle = "white";
var y = Math.floor(i*intGridWidth)+0.5
objContext.moveTo(0, y);
objContext.lineTo(objCanvas.width, y);
objContext.stroke();
}
Here's a fiddle demonstrating it with very thin and clean lines :
http://jsfiddle.net/dystroy/7NJ6w/
The fact that a line is drawn over all pixels it is over means the only way to draw an horizontal line with a width of exactly one pixel is to target the middle. I usually have this kind of util functions in my canvas based applications :
function drawThinHorizontalLine(c, x1, x2, y) {
c.lineWidth = 1;
var adaptedY = Math.floor(y)+0.5;
c.beginPath();
c.moveTo(x1, adaptedY);
c.lineTo(x2, adaptedY);
c.stroke();
}
Of course you'd better do it for vertical lines too to have a good looking page.

It doesn't look faded for me. Maybe it's something to do with your OS or PC, which is not able to render the drawing properly. I'm using Chrome 20 on Win 7. Test it out.

You have to define objContext.lineWidth like this:
objContext.lineWidth = 2;
I'm not sure why last line gets faded though.
See http://jsfiddle.net/jSCCY/

Related

Using parallax scrolling, cube has distortion

I am creating a 2d platformer right now, and I decided that I would use parallax scrolling.
So what I did is I had 3 tile maps, one for the background, one for the foreground, and one for on front of the foreground.
Each tile map would display the tiles at a different size.
Background -> 48px
Foreground -> 64px
On front of foreground -> 80px
I got the pixels from looking at other 3d games(such as Minecraft), when cubes are further a way. I wanted each tile to be as if the size of it is a cube.
I used the below code to calculate where each tile goes on the screen, based on its x, y, and size.
x - (cameraX * size / 64) + canvas.width / 2; // 64 is the size of the texture.
y - (cameraY * size / 64) + canvas.height / 2;
Here was the result:
As you can see the tiles in the background are moving slower.
However, when you jump, there would be white space between the tiles:
I understand why this is happening, it is because there should be a top face on the tile (as if it is a cube), but since it is only a square, it shows white space.
So I used this code to make it look as if it is a 3d cube.
var i = (size - size * 0.25);
while (i < size)
{
ctx.drawImage(images[this.type], getProperX(x*(i), i), getProperY(y*i, i), i, i);
// The first argument of getProperX/getProperY is the x/y, the second argument is the size of the tile.
i += 1;
}
This keeps drawing loads of squares, with a size slightly smaller than the last, so that the getProperX/Y function will display it in the right place.
Now they looks like cubes, so the problem is nearly fixed:
The only problem now, is that the length of the cubes are very long when you are looking on top/bottom of it, or to the right/left of it (as if it is distorted).
Why are the cubes/tiles so long, can anyone explain to me?
How would you go about fixing something like this?
Did I do something wrong in my parallax scrolling function getProperX/Y()? because I don't see why there is so much space between the distant tiles and the close ones.
Thanks for all help, very appreciated.

pixalate an image in html5 canvas

I've created a game that works with canvas, and i need it to be in a very low resolution to fit a software I'm working with. besically when I draw a diagonal line it should appear as a diagonal row of squares.
I did
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
but it's just blurry. How can I convert it?
the top picture is what it looks like now and the bottom is what i want it to look like
One approach is to use image smoothing disabled with a low-resolution canvas. Though you will get a blocky line, you will also get the anti-aliased pixels included. The only way to avoid this is to implement line algorithms etc. yourselves such as Bresenham (see below example).
You can also draw the lines, then run through the bitmap pixel by pixel and use a threshold value to filter the anti-aliased pixels away but this will give various results and is dependent on having isolated paths to work with, ie. draw to off-screen, filter with threshold, then draw result to main canvas.
An example:
var mctx = main.getContext("2d"),
lowRes = document.createElement("canvas"),
ctx = lowRes.getContext("2d");
// setup low-res canvas (invisible)
lowRes.width = 32;
lowRes.height = 20;
// setup main visible canvas
mctx.imageSmoothingEnabled =
mctx.msImageSmoothingEnabled =
mctx.mozImageSmoothingEnabled =
mctx.webkitImageSmoothingEnabled = false;
// draw a line to off-screen canvas
ctx.moveTo(0, lowRes.height);
ctx.lineTo(lowRes.width - 7, 4);
ctx.lineWidth=4;
ctx.strokeStyle = "#fff";
ctx.stroke();
// draw bacground on main canvas
mctx.fillRect(0,0,500,300);
// draw in low-res line
mctx.drawImage(lowRes, 0,0,lowRes.width,lowRes.height,
0,0,main.width,main.height);
<canvas id="main" width=500 height=300></canvas>
I would also like to propose to check out my Retro Context library (free/GPL3) which was made for this very reason. It has implemented all these line algorithms and has a full and simple API to access them (and much more "retro" related).
Optionally, you would need to implement these line algorithms yourselves. Here are some resources to help you get started if you chose this approach:
Bresenham line algorithm
Mid-point circle algorithm

svg.js strange interaction of scale and move/center

I'm not very familiar working with svgs in js but here is something that is definitely strange.
I'm having an arrow and then a path that is supposed to fill that arrow to a certain extend. looks like this:
Now my aim is to be able to scale the white part but it should still stay inside that arrow.
Now the weird thing is that I cannot figure out how move the white part back into the right place. I've tried different attempts.
here is my current code (it works for scaleFactor 1 but not for any other):
var draw = SVG('arrow').size(500, 500);
var arrowPath=draw.polyline('10,243.495 202.918,15.482 397.199,245.107').fill('none').stroke({ width: 20 });
var arrow=draw.group();
arrow.add(arrowPath.clone());
var scaleFactor=0.5;
var fillArrow=draw.path('M357.669,198.387c-41.747,35.357-95.759,56.678-154.751,56.678c-58.991,0-113.003-21.32-154.75-56.676l154.75-182.907 L357.669,198.387z');
fillArrow.fill('#ffffee');
var moveX=(arrowPath.width()/2-fillArrow.width()/2)/scaleFactor+9.5;
console.log(moveX);
fillArrow.center(arrowPath.cx(), arrowPath.cy()).scale(scaleFactor);
//another attempt was
fillArrow.move(moveX,0);
When you are scaling, rotating and translating in SVG you are doing coordinate transforms. That is, you are actually not changing the object you are drawing but the coordinate system that you are drawing the object in. Think of it as pixel has a certain size on your screen, and if your do svgObject.scale(0.5) the pixel becomes half the size.
So if you draw a square by path('M10,10 L20,10 L20,20 L10,20 z') and then apply scale(0.5) it will look like you have drawn a path that looks like path('M5,5 L10,5 L10,10 L5,10 Z')
This might sound strange at first but, but alot of geometrical calculations becomes much simpler when you can do this.
You want to scale around the tip of the arrow (make sure that does not move). Then you should place that point in the origo (0,0) and draw the object around that point. Do that in a group. Because then you can translate the group coordinate system to the correct position.
var draw = SVG('arrow').size(600, 600);
// create a group
var arrow = draw.group();
// Draw the arrow path in the group
// I have placed the "tip" of the arrow in (0,0)
var arrowPath = arrow.polyline('-250,250 0,0 250,250').fill('none').stroke({
width: 20
});
// Draw the fill arrow in the group. Again, the point
// I which to scale around is placed at (0,0)
var fillArrow = arrow.path('M0,0L150,150,-150,150z').fill('#ffffee');
// Move the group to the position we like to display it in the SVG
arrow.move(260, 20);
var scaleFactor = 0.5
fillArrow.scale(scaleFactor);
And here is a working example where you can test and change the scale factor.
http://jsfiddle.net/ZmGQk/1/
And here is a good explanation on how the translate, rotate and scale works.
http://commons.oreilly.com/wiki/index.php/SVG_Essentials/Transforming_the_Coordinate_System

Canvas label and scroll issues

I have been working on two different approaches to create a graphical canvas with html5 code, allowing graphical representation and horizontal scrolling of the graph. the canvas represents a timeline of sorts. as we scroll horizontally, the idea is to represent several years in the format of a timeline... example: say the historical development of computers... I m plotting points on the graph in reference to xy co-ordinates. this is currently se manually. later on I plan to make it based on sql queries. then as i scroll more, points plotted in future years/past years are displayed accordingly...giving it a continuous timeline feeling.
I have been trying to attempt this with 2 approaches in html5 canvas..some have suggested using SVG, silverlight, GDI +....
approach 1:-
http://jsfiddle.net/7KaKf/1/
method - a grid is created, points are plotted on the grid with a variable list, click mouse on the canvas - triggering is activated, drag canvas to scroll horizontally, click again on the canvas and scrolling is disabled.
advantage to this approach - horizontal scrolling works like a charm!!!
however, the issue in this approach is that i am not sure how to bind y axis lables on this grid such that every scrollable frame has a consistent label for both x axis and y axis.
note: you can view my next approach to see what i mean by labels.
approach 2:-
http://jsfiddle.net/WNpKE/10/
The issue with the 2nd approach, is mostly like in the function that capture the mouse scrolling/dragging event and tries to repaint the canvas elements:-
window.onmousemove = function (e) {
var evt = e || event;
if (dragging) {
var delta = evt.offsetX - lastX;
translated += delta;
//console.log(translated);
ctx.restore();
ctx.clearRect(0, 0, 930, 900);
ctx.save();
ctx.translate(translated, 0);
lastX = evt.offsetX;
timeline();
}
}
Another issue could be, even though timeline() is being recalled as the canvas scrolls, the grid is painted statically, between x = 65 and x = 930/ hence no other grid is being drawn.
Although labeling is possible with this approach (which was proving to be difficult with the first approach), the grid is not consistent and once i scroll out of the first frame, the grid dissappears.... although the plotted points in the future are still visible when we scroll.
In my first approach I use a grid that keeps repeating itself as we scroll on the canvas...however labeling becomes difficult with that...and in the 2nd approach, i label, however creating that style of repeating grid becomes difficult. I have come to quite the roadblock. somehow I need to combine both methods to create the solution. Can anyone help ?
If someone could also give me links to cool canvas related theory material. I would appreciate it. :)
updated 2nd approach and the solution :-
http://jsfiddle.net/WNpKE/12/
With this approach the y axis labels remain constant. the background grid is replicating. Although this is sort of the solution that I was looking for (it is not perfect), any modifications are most welcome.
I think you should stick with D3 library: http://d3js.org/. It's the absolute reference in terms of data visualizations, even it's not based on canvas, but there are a tons of examples and by inspecting the code you can learn a lot.
Another one would be paperjs, but this one is suited mostly for user interaction.
Although my solution is not perfect yet, but the solution can be found on:-
http://jsfiddle.net/WNpKE/12/
Solution:- creating the x-y grid separately as a function.
grid = (function (dX, dY) {
var can = document.createElement("canvas"),
ctx = can.getContext('2d');
can.width = dX;
can.height = dY;
// fill canvas color
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, dX, dY);
// x axis
ctx.strokeStyle = 'orange';
ctx.moveTo(.5, 0.5);
ctx.lineTo(dX + .5, 0.5);
ctx.stroke();
// y axis
ctx.moveTo(.5, .5);
ctx.lineTo(.5, dY + .5);
ctx.stroke();
return ctx.createPattern(can, 'repeat');
})(72, 50);

Fastest algorithm to draw a crossword grid in <canvas>?

I'm rendering a grid of cells, very much like the grid you find in a crossword puzzle, but using four different colors to fill each cell (not only black or white).
The grid size is about 160x120, and I need to render it as fast as possible, as it will be used to display a Cellular automaton animation.
I have tried two different approaches to render the grid:
Render each cell using something like:
var w = x + step;
var h = y + step;
canvasContext.fillStyle=cell.color;
canvasContext.fillRect(x+1,y+1,w-1,h-1);
canvasContext.strokeRect(x,y,w,h);
Render the all of cells without the border, and then render the grid lines using:
var XSteps = Math.floor(width/step);
canvasContext.fillStyle = gridColor;
for (var i = 0, len=XSteps; i<len; i++) {
canvasContext.fillRect(i*step, 0, 1, height);
}
//Similar thing for Y coord
Both algorithms perform poorly: it is slower to draw the grid than the cells in both cases. Am I missing something? How can I optimize those algorithms? Is there another way I should try?
Note: the grid moves, as the user can displace it or zoom the view.
The general question will be: what is the fastest algorithm to draw a grid of cells on a element?
The fastest way to do something is to not do it at all.
Draw your unchanging grid once on one canvas, and draw (and clear and redraw) your cellular automata on another canvas layered above (or below) that. Let the browser (in all it's native compiled optimized glory) handle dirtying and redrawing and compositing for you.
Or (better) if you are not going to change your grid size, just create a tiny image and let CSS fill it as the background.
Demo of CSS Background image to Canvas: http://jsfiddle.net/LdmFw/3/
Based on this excellent demo, here's a background image grid created entirely through CSS; with this you could change the size as desired (in whole-pixels increments).
Demo of CSS3 Grid to Canvas: http://jsfiddle.net/LdmFw/5/
If you must draw a grid, the fastest will be to just draw lines:
function drawGrid(ctx,size){
var w = ctx.canvas.width,
h = ctx.canvas.height;
ctx.beginPath();
for (var x=0;x<=w;x+=size){
ctx.moveTo(x-0.5,0); // 0.5 offset so that 1px lines are crisp
ctx.lineTo(x-0.5,h);
}
for (var y=0;y<=h;y+=size){
ctx.moveTo(0,y-0.5);
ctx.lineTo(w,y-0.5);
}
ctx.stroke(); // Only do this once, not inside the loops
}
Demo of grid drawing: http://jsfiddle.net/QScAk/4/
For m rows and n columns this requires m+n line draws in a single pass. Contrast this with drawing m×n individual rects and you can see that the performance difference can be quite significant.
For example, a 512×512 grid of 8×8 cells would take 4,096 fillRect() calls in the naive case, but only 128 lines need to be stroked in a single stroke() call using the code above.
It's really hard to help without seeing all the code to know where the performance is going, but just off the bat:
Instead of drawing a background grid using stroke, can you draw it using one call to drawImage? That will be much faster. If its truly static then you can just set a css background-image on the canvas to an image of the grid you want.
You're using fillRect and strokeRect a lot and these can probably be replaced with several calls to rect() (the path command) and only a single call to fill at the very end. So all the filled cells are rendered at once with a single filling (or stroking or both) command.
Set the fillStyle/strokeStyle as little as possible (not inside loops if you can avoid it)
You are using fill to draw the lines; it would be faster, I think, to define a path and stroke it:
canvasContext.beginPath();
var XSteps = Math.floor(width / step);
canvasContext.fillStyle = gridColor;
var x = 0;
for (var i = 0, len = XSteps; i < len; i++) {
canvasContext.moveTo(x, 0);
canvasContext.lineTo(x, height);
x += step;
}
// similar for y
canvasContext.stroke();

Categories